import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GraphicsPanel extends JPanel implements KeyListener {
	private static final long serialVersionUID = -3887626951366242085L;
	private int windowWidth;
	private int windowHeight;
	private BufferedImage buffer;
	private BufferedImage menu;
	private BufferedImage saveWindow;
	private Sprite playerMap;
	private Sprite playerBattle;
	private Player playerData;
	private int x, y, curMap, randEncounter, trans, off, pauseCursor, prevMap,
	beginCursor, saveCursor, confirmCursor, scrollCursor, scrollIndex, victoryIndex,
	invCursor, shopCursor, shopIndex, animCounter, battleIndex, battleCursor;
	private Map[] maps;
	private Battle battle;
	private HashMap<String, BufferedImage> enemyImages;
	private HashMap<String, Player> enemyData;
	private ArrayList<Action> actions;
	private ArrayList<Animation> animates;
	private String[] pauseOptions;
	private Polygon[] battleWindows;
	private boolean change, halt, mapMove, playerMove, wasCenter, writing, endGame;;
	private Font comicbook; // I do not own rights to comicbook. It is a
	// free-to-use font

	public enum State {
		Begin, Map, Transition, PostTransition, Pause, Inventory, Save, Credits, 
		Status, Load, Shop, Message, Confirm, None, BattleMessage, BattleForward,
		BattleBackward, BattleMenu, BattleCursor, BattleEnemyAttack, BattleEnemyDamage,
		BattlePlayerAttack, BattlePlayerDamage, BattleVictory, BattlePlayerDeath,
		BattleEnemyDeath, GameOver, BattleQueue, BattlePlayerNumber, BattlePostAttack,
		BattleEnemyAnimation, BattlePlayerAnimation, BattleEnemyNumber, BattleInventory, GameWon
	};

	private State state;
	private State substate;
	private String[] beginOptions;
	private String[] creditLines;
	private String message;
	private File save1, save2;
	private ArrayList<Item> items;
	private ArrayList<Equip> equips;
	private BufferedImage invWindow;
	private BufferedImage statBar;
	private short[] invertTable;

	public GraphicsPanel() {
		setIgnoreRepaint(true);
		addKeyListener(this);
		setFocusable(true);
	}

	public void keyPressed(KeyEvent e) {
		if (state == null) {
			e.consume();
			System.out.println("Consumed");
		}
		if (state.equals(State.Map)) {
			if (e.getKeyCode() == KeyEvent.VK_LEFT) {
				if (!(playerMap.right || playerMap.up || playerMap.down)) {
					halt = false;
					playerMap.left = true;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
				if (!(playerMap.left || playerMap.up || playerMap.down)) {
					halt = false;
					playerMap.right = true;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_UP) {
				if (!(playerMap.right || playerMap.left || playerMap.down)) {
					halt = false;
					playerMap.up = true;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
				if (!(playerMap.right || playerMap.up || playerMap.left)) {
					halt = false;
					playerMap.down = true;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				state = State.Pause;
				pauseCursor = 0;
			}
			else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (x % 24 == 0 && y % 24 == 0 && playerMap.x % 24 == 0
						&& playerMap.y % 24 == 0) {
					int i = (x / 24) + (playerMap.x / 24);
					int j = (y / 24) + (playerMap.y / 24);
					if (playerMap.getState() < 3)
						j += 1;
					else if (playerMap.getState() < 6)
						j -= 1;
					else if (playerMap.getState() < 9)
						i += 1;
					else
						i -= 1;
					if (i >= 0 && i < (maps[curMap].image().getHeight() / 24)
							&& j >= 0
							&& j < (maps[curMap].image().getWidth() / 24)) {
						if (maps[curMap].typeAt(i, j) == 3)
							state = State.Shop;
						else if (maps[curMap].typeAt(i, j) == 4) {
							substate = state;
							message = "Rest?";
							state = State.Confirm;
						} else if (maps[curMap].typeAt(i, j) == 5) {
							if (playerData.getLevel() >= maps[curMap]
									.getWarpLevel()) {
								if (curMap < maps.length - 1) {
									playerMap.x = 24;
									playerMap.y = 24;
									x = 0;
									y = 0;
									curMap++;
								} else {
									ArrayList<Player> good = new ArrayList<Player>();
									ArrayList<Player> bad = new ArrayList<Player>();
									good.add(playerData);
									bad.add(enemyData.get("Carl Conway"));
									battle = new Battle(good, bad, actions);
									endGame = true;
								}
							} else {
								message = "Not strong enough yet";
								substate = State.Map;
								state = State.Message;
							}
						}
					}
				}
			}
		} else if (state.equals(State.GameOver)) {
			if (e.getKeyCode() == KeyEvent.VK_ENTER){
				initialize();
				state = State.Begin;
			}
		}
		else if(state.equals(State.GameWon)){
			if (e.getKeyCode() == KeyEvent.VK_ENTER){
				endGame = false;
				curMap = maps.length - 1;
				playerData.setGold(playerData.getGold() + 30000);
				state = State.Map;
			}
		}
		else if (state.equals(State.Pause)) {
			if (e.getKeyCode() == KeyEvent.VK_UP)
				pauseCursor -= 1;
			else if (e.getKeyCode() == KeyEvent.VK_DOWN)
				pauseCursor += 1;
			else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				pauseCursor = 0;
				state = State.Map;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (pauseCursor == 0) // Status
					state = State.Status;
				else if (pauseCursor == 1) // Inventory
					state = State.Inventory;
				else if (pauseCursor == 2) // Save
					state = State.Save;
				else
					// Exit
					state = State.Begin;
			}
		} else if (state.equals(State.Begin)) {
			if (e.getKeyCode() == KeyEvent.VK_UP)
				beginCursor -= 1;
			else if (e.getKeyCode() == KeyEvent.VK_DOWN)
				beginCursor += 1;
			else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (beginCursor == 0) // In the future, will lead to the intro
					// 'movie'
					state = State.Map;
				else if (beginCursor == 1) { // Bring up load window
					state = State.Load;
				} else if (beginCursor == 2) {
					state = State.Credits;
				} else {
					System.exit(0);
				}
			}
		} else if (state.equals(State.Credits)) {
			if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				state = State.Begin;
			}
		} else if (state.equals(State.Confirm)) {
			if (e.getKeyCode() == KeyEvent.VK_UP)
				confirmCursor--;
			else if (e.getKeyCode() == KeyEvent.VK_DOWN)
				confirmCursor++;
			else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (confirmCursor == 1) {
					if (substate.equals(State.Save)) {
						try {
							saveGame(saveCursor);
						} catch (IOException e1) {
							e1.printStackTrace();
							System.exit(0);
						}
						state = substate;
						message = "";
						substate = State.None;
					} else if (substate.equals(State.Map)) {
						playerData.setCurHp(playerData.getHp());
						playerData.setCurMp(playerData.getMp());
						message = "Fully recovered";
						substate = State.Map;
						state = State.Message;
					} else if (substate.equals(State.Status)) {
						String temp = playerData.getActions().get(
								scrollCursor + scrollIndex);
						Action tempA = Utilities.findSomething(temp, actions);
						playerData.setCurMp(playerData.getCurMp()
								- tempA.getManaCost());
						int heal = Integer
								.parseInt(tempA.getCommand()
										.substring(
												tempA.getCommand().lastIndexOf(
														" ") + 1));
						int cap = playerData.getHp() - playerData.getCurHp();
						if (heal > cap)
							heal = cap;
						playerData.setCurHp(playerData.getCurHp() + heal);
						message = heal + "hp recovered";
						substate = State.Status;
						state = State.Message;
					} else if (substate.equals(State.Inventory)) {
						if (invCursor == 0) {
							Equip temp = playerData.getHelm();
							playerData.equipHelm(new Equip(
									playerData.getInv().helms.get(scrollIndex
											+ scrollCursor), 1));
							if (playerData.getInv().helms.get(
									scrollIndex + scrollCursor).getQty() <= 0)
								playerData.getInv().helms.remove(scrollIndex
										+ scrollCursor);
							playerData.getInv().add(temp);
							message = "Equipped";
							substate = State.Inventory;
							state = State.Message;
						} else if (invCursor == 1) {
							Equip temp = playerData.getArmor();
							playerData.equipArmor(new Equip(
									playerData.getInv().armors.get(scrollIndex
											+ scrollCursor), 1));
							if (playerData.getInv().armors.get(
									scrollIndex + scrollCursor).getQty() <= 0)
								playerData.getInv().armors.remove(scrollIndex
										+ scrollCursor);
							playerData.getInv().add(temp);
							message = "Equipped";
							substate = State.Inventory;
							state = State.Message;
						} else if (invCursor == 2) {
							Equip temp = playerData.getWeapon();
							playerData.equipWeapon(new Equip(playerData
									.getInv().weapons.get(scrollIndex
											+ scrollCursor), 1));
							if (playerData.getInv().weapons.get(
									scrollIndex + scrollCursor).getQty() <= 0)
								playerData.getInv().weapons.remove(scrollIndex
										+ scrollCursor);
							playerData.getInv().add(temp);
							message = "Equipped";
							substate = State.Inventory;
							state = State.Message;
						} else if (invCursor == 3) {
							Item item = new Item(
									playerData.getInv().items.get(scrollIndex
											+ scrollCursor), 1);
							if (playerData.getInv().items.get(
									scrollIndex + scrollCursor).getQty() <= 0)
								playerData.getInv().items.remove(scrollIndex
										+ scrollCursor);
							boolean hp = item.getCommand().contains("recover");
							int heal = Integer
									.parseInt(item
											.getCommand()
											.substring(
													item.getCommand()
													.lastIndexOf(" ") + 1));
							int cap = (hp ? playerData.getHp() : playerData
									.getMp())
									- (hp ? playerData.getCurHp() : playerData
											.getCurMp());
							if (heal > cap)
								heal = cap;
							if (hp)
								playerData.setCurHp(playerData.getCurHp()
										+ heal);
							else
								playerData.setCurMp(playerData.getCurMp()
										+ heal);
							message = (hp ? "hp:" : "mp:") + heal
									+ " recovered";
							substate = State.Inventory;
							state = State.Message;
						}
					} else if (substate.equals(State.Shop)) {
						if (message.equals("Equip?")) {
							Equip tryEquip = Utilities.findSomething(
									maps[curMap].equipsForSale()[scrollIndex
									                             + scrollCursor], equips);
							if (tryEquip.getType().equals(Equip.Type.Helm)) {
								Equip temp = playerData.getHelm();
								int index = Utilities.findIndex(tryEquip.getName(), playerData.getInv().helms);
								Equip real = playerData.getInv().helms
										.get(index);
								playerData.equipHelm(new Equip(real, 1)); // --
								if (real.getQty() <= 0) {
									playerData.getInv().helms.remove(real);
								}
								playerData.getInv().add(temp);
								message = "Equipped";
								substate = State.Shop;
								state = State.Message;
							} else if (tryEquip.getType().equals(
									Equip.Type.Armor)) {
								Equip temp = playerData.getArmor();
								int index = Utilities.findIndex(tryEquip.getName(), playerData.getInv().armors);
								Equip real = playerData.getInv().armors
										.get(index);
								playerData.equipArmor(new Equip(real, 1)); // --

								if (real.getQty() <= 0) {
									playerData.getInv().armors.remove(real);
								}

								playerData.getInv().add(temp);
								message = "Equipped";
								substate = State.Shop;
								state = State.Message;
							} else if (tryEquip.getType().equals(
									Equip.Type.Weapon)) {
								Equip temp = playerData.getWeapon();
								int index = Utilities.findIndex(tryEquip.getName(), playerData.getInv().weapons);
								Equip real = playerData.getInv().weapons
										.get(index);
								playerData.equipWeapon(new Equip(real, 1)); // --

								if (real.getQty() <= 0) {
									playerData.getInv().weapons.remove(real);
								}

								playerData.getInv().add(temp);
								message = "Equipped";
								substate = State.Shop;
								state = State.Message;
							}
						} else if (invCursor == 0) {
							if (shopIndex == 1) {
								if (scrollIndex + scrollCursor < playerData
										.getInv().helms.size()) {
									Equip helm = playerData.getInv().helms.get(scrollCursor + scrollIndex);
									playerData.setGold(helm.getSellPrice()
											+ playerData.getGold());
									helm.setQty(helm.getQty() - 1);
									if (helm.getQty() <= 0) {
										playerData.getInv().helms.remove(helm);
									}
									state = State.Message;
									message = "Sold";
								}
							} else {
								if (scrollIndex + scrollCursor < maps[curMap]
										.equipsForSale().length) {
									// Attempt to buy equip
									Equip temp = Utilities
											.findSomething(
													maps[curMap]
															.equipsForSale()[scrollIndex
															                 + scrollCursor],
															                 equips);
									int cost = temp.getCost();
									playerData.setGold(playerData.getGold()
											- cost);
									if (temp.getType().equals(Equip.Type.Armor)) {
										int index = Utilities.findIndex(temp.getName(), playerData.getInv().armors);
										if (index == -1) {
											playerData.getInv().add(temp);
										} else {
											Equip real = playerData.getInv().armors
													.get(index);
											real.setQty(real.getQty() + 1);
										}
									} else if (temp.getType().equals(
											Equip.Type.Helm)) {
										int index = Utilities.findIndex(temp.getName(), playerData.getInv().helms);
										if (index == -1) {
											playerData.getInv().add(temp);
										} else {
											Equip real = playerData.getInv().helms
													.get(index);
											real.setQty(real.getQty() + 1);
										}
									} else if (temp.getType().equals(
											Equip.Type.Weapon)) {
										int index = Utilities.findIndex(temp.getName(), playerData.getInv().weapons);
										if (index == -1) {
											playerData.getInv().add(temp);
										} else {
											Equip real = playerData.getInv().weapons
													.get(index);
											real.setQty(real.getQty() + 1);
										}
									}
									message = "Equip?";
								}
							}
						} else if (invCursor == 1) {
							if (shopIndex == 1) {
								if (scrollIndex + scrollCursor < playerData
										.getInv().armors.size()) {
									// Attempt to sell armor
									Equip armor = playerData.getInv().armors.get(scrollCursor + scrollIndex);
									playerData.setGold(armor.getSellPrice()
											+ playerData.getGold());
									armor.setQty(armor.getQty() - 1);
									if (armor.getQty() <= 0) {
										playerData.getInv().armors
										.remove(armor);
									}
									state = State.Message;
									message = "Sold";
								}
							} else {
								if (scrollIndex + scrollCursor < maps[curMap]
										.itemsForSale().length) {
									// Attempt to buy item
									Item temp = Utilities
											.findSomething(
													maps[curMap].itemsForSale()[scrollIndex
													                            + scrollCursor],
													                            items);
									int cost = temp.getCost();
									playerData.setGold(playerData.getGold()
											- cost);
									int index = Utilities.findIndex(temp.getName(), playerData.getInv().items);
									if (index == -1) {
										playerData.getInv().add(temp);
									} else {
										Item real = playerData.getInv().items
												.get(index);
										real.setQty(real.getQty() + 1);
									}
									state = State.Message;
									message = "Purchased";
								}
							}
						} else if (invCursor == 2) {
							if (shopIndex == 1) {
								if (scrollIndex + scrollCursor < playerData
										.getInv().weapons.size()) {
									Equip weapon = playerData.getInv().weapons.get(scrollCursor + scrollIndex);
									playerData.setGold(weapon.getSellPrice()
											+ playerData.getGold());
									weapon.setQty(weapon.getQty() - 1);
									if (weapon.getQty() <= 0) {
										playerData.getInv().weapons
										.remove(weapon);
									}
									state = State.Message;
									message = "Sold";
								}
							} else {
								if (scrollIndex + scrollCursor < maps[curMap]
										.getAbilities().length) {
									// Attempt to buy action
									int extra = 0;
									for(int i = 0; i <= scrollIndex + scrollCursor; i++){
										if(Utilities.findIndex(maps[curMap].getAbilities()[i + extra], playerData.getActions()) != -1){
											extra++;
											i--;
										}
									}
									Action temp = Utilities
											.findSomething(
													maps[curMap].getAbilities()[scrollIndex + extra
													                            + scrollCursor],
													                            actions);
									int cost = maps[curMap].abilitySale(temp
											.getName());
									playerData.setGold(playerData.getGold()
											- cost);
									playerData.getActions().add(temp.getName());
									state = State.Message;
									message = "Purchased";
								}
							}
						} else if (invCursor == 3 && shopIndex == 1) {
							if (scrollIndex + scrollCursor < playerData
									.getInv().items.size()) {
								Item item = Utilities.findSomething(
										maps[curMap].itemsForSale()[scrollIndex
										                            + scrollCursor],
										                            playerData.getInv().items);
								playerData.setGold(item.getSellPrice()
										+ playerData.getGold());
								item.setQty(item.getQty() - 1);
								if (item.getQty() <= 0) {
									playerData.getInv().items.remove(item);
								}
								state = State.Message;
								message = "Sold";
							}
						}
					}
				} else {
					if (message.equals("Equip?")) {
						state = State.Message;
						message = "Purchased";
					} else {
						state = substate;
						message = "";
						substate = State.None;
					}
				}
				confirmCursor = 0;
			}
		} else if (state.equals(State.Save) || state.equals(State.Load)) {
			if (e.getKeyCode() == KeyEvent.VK_LEFT)
				saveCursor -= 1;
			else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
				saveCursor += 1;
			else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				if (state.equals(State.Save))
					state = State.Pause;
				else if (state.equals(State.Load))
					state = State.Begin;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (state.equals(State.Save)) {
					if ((saveCursor == 0 ? save1 : save2) != null) {
						substate = state;
						message = "Overwrite?";
						state = State.Confirm;
					} else {
						try {
							saveGame(saveCursor);
						} catch (IOException e1) {
							e1.printStackTrace();
							System.exit(0);
						}
					}
				} else if (state.equals(State.Load)) {
					if (saveCursor == 0 && save1 != null) {
						try {
							loadGame(save1);
						} catch (IOException e1) {
							e1.printStackTrace();
							System.exit(0);
						}
						state = State.Map;
					} else if (saveCursor == 1 && save2 != null) {
						try {
							loadGame(save2);
						} catch (IOException e1) {
							e1.printStackTrace();
							System.exit(0);
						}
						state = State.Map;
					}
				}
			}
		} else if (state.equals(State.Message)) {
			if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				state = substate;
				substate = State.None;
				message = "";
			}
		} else if (state.equals(State.Shop) && substate.equals(State.None)) {
			if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				if (shopCursor == 0) {
					invCursor = 0;
					scrollIndex = 0;
					scrollCursor = 0;
					state = State.Map;
				} else {
					invCursor = 0;
					shopCursor = 0;
					scrollCursor = 0;
					scrollIndex = 0;
					shopIndex = -1;
				}
			}
			if (e.getKeyCode() == KeyEvent.VK_LEFT) {
				invCursor--;
				if (shopCursor == 1) {
					scrollIndex = 0;
					scrollCursor = 0;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
				invCursor++;
				if (shopCursor == 1) {
					scrollIndex = 0;
					scrollCursor = 0;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_UP) {
				if (shopCursor == 1)
					scrollCursor--;

			} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
				if (shopCursor == 1)
					scrollCursor++;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (shopCursor == 0) {
					shopIndex = invCursor;
					invCursor = 0;
					shopCursor = 1;
				} else {
					boolean confirm = false;
					if (invCursor == 0) {
						if (shopIndex == 1) {
							if (scrollIndex + scrollCursor < playerData
									.getInv().helms.size()) {
								confirm = true;
							}
						} else {
							if (scrollIndex + scrollCursor < maps[curMap]
									.equipsForSale().length) {
								// Attempt to buy equip
								Equip item = Utilities
										.findSomething(
												maps[curMap].equipsForSale()[scrollIndex
												                             + scrollCursor], equips);
								int playerGold = playerData.getGold();
								if (item.getCost() <= playerGold) {
									confirm = true;
								} else {
									confirm = false;
								}
							}
						}
					} else if (invCursor == 1) {
						if (shopIndex == 1) {
							if (scrollIndex + scrollCursor < playerData
									.getInv().armors.size()) {
								// Attempt to sell armor
								confirm = true;
							}
						} else {
							if (scrollIndex + scrollCursor < maps[curMap]
									.itemsForSale().length) {
								// Attempt to buy item
								Item item = Utilities.findSomething(
										maps[curMap].itemsForSale()[scrollIndex
										                            + scrollCursor], items);
								int playerGold = playerData.getGold();
								if (item.getCost() <= playerGold) {
									confirm = true;
								} else {
									confirm = false;
								}
							}
						}
					} else if (invCursor == 2) {
						if (shopIndex == 1) {
							if (scrollIndex + scrollCursor < playerData
									.getInv().weapons.size()) {
								// Attempt to sell weapon
								confirm = true;
							}
						} else {
							if (scrollIndex + scrollCursor < maps[curMap]
									.getAbilities().length) {
								// Attempt to buy action
								int count = 0;
								for(int i = 0; i < maps[curMap].getAbilities().length; i++){
									if(Utilities.findIndex(maps[curMap].getAbilities()[i], playerData.getActions()) == -1){
										count++;
									}
								}
								if(scrollIndex + scrollCursor >= count)
									return;
								Action item = Utilities.findSomething(
										maps[curMap].getAbilities()[scrollIndex
										                            + scrollCursor], actions);
								int cost = maps[curMap].abilitySale(item
										.getName());
								int playerGold = playerData.getGold();
								if (cost <= playerGold) {
									confirm = true;
								} else {
									confirm = false;
								}
							}
						}
					} else if (invCursor == 3 && shopIndex == 1) {
						if (scrollIndex + scrollCursor < playerData.getInv().items
								.size()) {
							// Attempt to sell item
							confirm = true;
						}
					}
					if (confirm) {
						// state
						// substate
						// message
						substate = state;
						state = State.Confirm;
						message = ((shopIndex == 1) ? "Sell?" : "Buy?");
					}
				}
			}
		} else if (state.equals(State.Status)) {
			if (e.getKeyCode() == KeyEvent.VK_UP)
				scrollCursor -= 1;
			else if (e.getKeyCode() == KeyEvent.VK_DOWN)
				scrollCursor += 1;
			else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				state = State.Pause;
				scrollCursor = 0;
				scrollIndex = 0;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER
					&& playerData.getCurHp() != playerData.getHp()
					&& scrollCursor + scrollIndex < playerData.getActions()
					.size()) {
				String temp = playerData.getActions().get(
						scrollCursor + scrollIndex);
				Action tempA = Utilities.findSomething(temp, actions);
				if (tempA.getCommand().contains("recover")
						&& playerData.getCurMp() >= tempA.getManaCost()) {
					substate = state;
					state = State.Confirm;
					message = "Cast?";
				}
			}
		} else if (state.equals(State.BattleMenu)) {
			if (e.getKeyCode() == KeyEvent.VK_UP)
				scrollCursor -= 1;
			else if (e.getKeyCode() == KeyEvent.VK_DOWN)
				scrollCursor += 1;
			else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				String act = "";
				boolean item = false;
				if (scrollIndex + scrollCursor == 0)
					act = "Attack";
				else if (scrollIndex + scrollCursor - 1 < playerData
						.getActions().size())
					act = playerData.getActions().get(
							scrollIndex + scrollCursor - 1);
				else if (scrollIndex + scrollCursor - 1 == playerData
						.getActions().size())
					act = "Run";
				else if(scrollIndex + scrollCursor - 2 == playerData.getActions().size())
					item = true;
				if(item){
					state = State.BattleInventory;
				}
				else{
					if(Utilities.findSomething(act, actions).getManaCost() <= playerData.getCurMp()){
						battle.setAction(Utilities.findSomething(act, actions));
						state = State.BattleCursor;
						substate = State.BattleMenu;
						invCursor = 0;
						while(!(battle.getBaddies().get(invCursor).getCurHp() > 0))
							invCursor++;
					}
				}
			}
		} 
		else if(state.equals(State.BattleInventory)){
			if(e.getKeyCode() == KeyEvent.VK_UP)
				battleCursor--;
			else if(e.getKeyCode() == KeyEvent.VK_DOWN){
				battleCursor++;
			}
			else if(e.getKeyCode() == KeyEvent.VK_ENTER){
				if (battleIndex + battleCursor < playerData.getInv().items
						.size()) {
					Item temp = playerData.getInv().items.get(battleIndex
							+ battleCursor);
					int qty = temp.getQty();
					if(qty == 1)
						playerData.getInv().items.remove(temp);
					else
						temp.setQty(qty - 1);
					Action a = new Action(temp.getName(), temp.getCommand(), temp.getDesc(), 0);
					battle.setAction(a);
					state = State.BattleCursor;
					substate = State.BattleInventory;
					invCursor = 0;
				}
			}
			else if(e.getKeyCode() == KeyEvent.VK_ESCAPE){
				battleIndex = 0;
				battleCursor = 0;
				state = State.BattleMenu;
			}
		}
		else if (state.equals(State.BattleCursor)) {
			if (e.getKeyCode() == KeyEvent.VK_LEFT
					&& !battle.playerAction().getDescription()
					.contains("all foes")
					&& battle.playerAction().getCommand().contains("damage")) {
				int old = invCursor;
				invCursor -= 1;
				if (invCursor < 0)
					invCursor = battle.getBaddies().size() - 1;
				while (invCursor != old
						&& battle.getBaddies().get(invCursor).getCurHp() == 0) {
					invCursor--;
					if (invCursor < 0)
						invCursor = battle.getBaddies().size() - 1;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_RIGHT
					&& !battle.playerAction().getDescription()
					.contains("all foes")
					&& battle.playerAction().getCommand().contains("damage")) {
				int old = invCursor;
				invCursor += 1;
				if (invCursor >= battle.getBaddies().size())
					invCursor = 0;
				while (invCursor != old
						&& battle.getBaddies().get(invCursor).getCurHp() == 0) {
					invCursor++;
					if (invCursor >= battle.getBaddies().size())
						invCursor = 0;
				}
			} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				if(substate.equals(State.BattleInventory))
					playerData.getInv().add(Utilities.findSomething(battle.playerAction().getName(), items));
				state = substate;
				substate = State.None;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				Player[] enm = null;
				if (battle.playerAction().getDescription().contains("all foes")) {
					enm = new Player[battle.getBaddies().size()];
					for (int i = 0; i < enm.length; i++) {
						enm[i] = battle.getBaddies().get(i);
					}
				} else if (battle.playerAction().getCommand()
						.contains("damage")) {
					enm = new Player[1];
					enm[0] = battle.getBaddies().get(invCursor);
				} else {
					enm = new Player[1];
					enm[0] = playerData;
				}
				battle.setTarget(enm);
				substate = State.BattleQueue;
				playerBattle.right = true;
				animCounter = 4;
				state = State.BattleBackward;
				playerBattle.setState(5);
				invCursor = 0;
				scrollIndex = 0;
				scrollCursor = 0;
			}
		} else if (state.equals(State.Inventory) && substate.equals(State.None)) {
			if (e.getKeyCode() == KeyEvent.VK_LEFT) {
				invCursor--;
				scrollIndex = 0;
				scrollCursor = 0;
			} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
				invCursor++;
				scrollIndex = 0;
				scrollCursor = 0;
			} else if (e.getKeyCode() == KeyEvent.VK_UP) {
				scrollCursor--;
			} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
				scrollCursor++;
			} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
				if (invCursor == 0) {
					if (scrollIndex + scrollCursor < playerData.getInv().helms
							.size()) {
						Equip temp = playerData.getInv().helms.get(scrollIndex
								+ scrollCursor);
						if (temp.getName().equals(
								playerData.getHelm().getName())) {
							substate = state;
							state = State.Message;
							message = "Already Equipped";
						} else {
							substate = state;
							state = State.Confirm;
							message = "Equip?";
						}
					}
				} else if (invCursor == 1) {
					if (scrollIndex + scrollCursor < playerData.getInv().armors
							.size()) {
						Equip temp = playerData.getInv().armors.get(scrollIndex
								+ scrollCursor);
						if (temp.getName().equals(
								playerData.getArmor().getName())) {
							substate = state;
							state = State.Message;
							message = "Already Equipped";
						} else {
							substate = state;
							state = State.Confirm;
							message = "Equip?";
						}
					}
				} else if (invCursor == 2) {
					if (scrollIndex + scrollCursor < playerData.getInv().weapons
							.size()) {
						Equip temp = playerData.getInv().weapons
								.get(scrollIndex + scrollCursor);
						if (temp.getName().equals(
								playerData.getWeapon().getName())) {
							substate = state;
							state = State.Message;
							message = "Already Equipped";
						} else {
							substate = state;
							state = State.Confirm;
							message = "Equip?";
						}
					}
				} else if (invCursor == 3) {
					if (scrollIndex + scrollCursor < playerData.getInv().items
							.size()) {
						Item temp = playerData.getInv().items.get(scrollIndex
								+ scrollCursor);
						boolean hp = temp.getCommand().startsWith("recover");
						if ((hp ? playerData.getCurHp() : playerData.getCurMp()) < (hp ? playerData
								.getHp() : playerData.getMp())) {
							substate = state;
							state = State.Confirm;
							message = "Use?";
						}
					}
				}
			} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				state = State.Pause;
				scrollIndex = 0;
				scrollCursor = 0;
				invCursor = 0;
			}
		}
		else if(state.equals(State.BattleVictory)){
			if(e.getKeyCode() == KeyEvent.VK_ENTER)
				animCounter = 0;
		}
	}

	private void saveGame(int gameNum) throws IOException {
		writing = true;
		FileOutputStream fos;
		if (gameNum == 0) {
			if (save1 == null) { // File does not exist
				save1 = new File("MMsav1.sav");
				save1.createNewFile();
			}
			fos = new FileOutputStream(save1);
		} else {
			if (save2 == null) { // File does not exist
				save2 = new File("MMsav2.sav");
				save2.createNewFile();
			}
			fos = new FileOutputStream(save2);
		}
		String save = playerData.getLevel() + "";
		save += "\n" + playerData.getExp();
		save += "\n" + playerData.getBaseHp();
		save += "\n" + playerData.getCurHp();
		save += "\n" + playerData.getBaseMp();
		save += "\n" + playerData.getCurMp();
		save += "\n" + playerData.getBaseMdef();
		save += "\n" + playerData.getBaseDef();
		save += "\n" + playerData.getBaseStr();
		save += "\n" + playerData.getBaseInt();
		save += "\n" + playerData.getSpeed();
		save += "\n" + playerData.getGold();
		save += "\n" + playerMap.x + " " + playerMap.y;
		save += "\n" + x + " " + y + " " + curMap;
		save += "\n"
				+ (playerData.getHelm() == null ? "null" : playerData.getHelm()
						.getName());
		save += "\n"
				+ (playerData.getArmor() == null ? "null" : playerData
						.getArmor().getName());
		save += "\n"
				+ (playerData.getWeapon() == null ? "null" : playerData
						.getWeapon().getName());
		save += "\n: ";
		String second = "";
		for (int i = 0; i < playerData.getInv().helms.size(); i++) {
			save += (i != 0 ? " " : "")
					+ playerData.getInv().helms.get(i).getName() + ":";
			second += playerData.getInv().helms.get(i).getQty() + " ";
		}
		save += "\n";
		save += second.trim() + "\n: ";
		second = "";

		for (int i = 0; i < playerData.getInv().armors.size(); i++) {
			save += (i != 0 ? " " : "")
					+ playerData.getInv().armors.get(i).getName() + ":";
			second += playerData.getInv().armors.get(i).getQty() + " ";
		}
		save += "\n";
		save += second.trim() + "\n: ";
		second = "";
		for (int i = 0; i < playerData.getInv().weapons.size(); i++) {
			save += (i != 0 ? " " : "")
					+ playerData.getInv().weapons.get(i).getName() + ":";
			second += playerData.getInv().weapons.get(i).getQty() + " ";
		}
		save += "\n";
		save += second.trim() + "\n: ";
		second = "";
		for (int i = 0; i < playerData.getInv().items.size(); i++) {
			save += (i != 0 ? " " : "")
					+ playerData.getInv().items.get(i).getName() + ":";
			second += playerData.getInv().items.get(i).getQty() + " ";
		}
		save += "\n";
		save += second.trim() + "\n: ";
		for (int i = 0; i < playerData.getActions().size(); i++) {
			save += (i != 0 ? " " : "") + playerData.getActions().get(i) + ":";
		}
		byte[] encrypted = Crypt.Encrypt(save);
		fos.write(encrypted);
		fos.close();
		writing = false;
		message = "Save succesful";
		substate = State.Save;
		state = State.Message;
	}

	public Player peekGame(File save) throws IOException {
		FileInputStream fis = new FileInputStream(save);
		byte[] data = new byte[fis.available()];
		fis.read(data);
		fis.close();
		String saveData = Crypt.Decrypt(data);
		Scanner sc = new Scanner(saveData);
		int[] stats = new int[12];
		for (int i = 0; i < 12; i++) {
			try {
				stats[i] = Integer.parseInt(sc.nextLine());
			} catch (Exception e) {
				e.printStackTrace();
				System.exit(0);
			}
		}
		sc.nextLine();
		sc.nextLine();
		Equip helm = Utilities.findSomething(sc.nextLine(), equips);
		Equip armor = Utilities.findSomething(sc.nextLine(), equips);
		Equip weapon = Utilities.findSomething(sc.nextLine(), equips);
		return new Player("Maleable Man", stats, helm, armor, weapon, null,
				null);
	}

	public void loadGame(File save) throws IOException {
		FileInputStream fis = new FileInputStream(save);
		byte[] data = new byte[fis.available()];
		fis.read(data);
		fis.close();
		String saveData = Crypt.Decrypt(data).trim();
		Scanner sc = new Scanner(saveData);
		int[] stats = new int[12];
		for (int i = 0; i < 12; i++) {
			stats[i] = Integer.parseInt(sc.nextLine());
		}
		Scanner line = new Scanner(sc.nextLine());
		playerMap.x = line.nextInt();
		playerMap.y = line.nextInt();
		line = new Scanner(sc.nextLine());
		x = line.nextInt();
		y = line.nextInt();
		curMap = line.nextInt();
		Equip helm = Utilities.findSomething(sc.nextLine(), equips);
		Equip armor = Utilities.findSomething(sc.nextLine(), equips);
		Equip weapon = Utilities.findSomething(sc.nextLine(), equips);
		ArrayList<Equip> helms = new ArrayList<Equip>();
		ArrayList<Equip> armors = new ArrayList<Equip>();
		ArrayList<Equip> weapons = new ArrayList<Equip>();
		ArrayList<Item> items = new ArrayList<Item>();
		ArrayList<String> actions = new ArrayList<String>();
		line = new Scanner(sc.nextLine());
		while (line.hasNext()) {
			Equip temp = Utilities.findSomething(readToColon(line), equips);
			if (temp != null)
				helms.add(temp);
		}
		line = new Scanner(sc.nextLine());
		int count = 0;
		while(line.hasNext()){
			int qty = line.nextInt();
			helms.get(count).setQty(qty);
			count++;
		}
		line = new Scanner(sc.nextLine());
		while (line.hasNext()) {
			Equip temp = Utilities.findSomething(readToColon(line), equips);
			if (temp != null)
				armors.add(temp);
		}
		line = new Scanner(sc.nextLine());
		count = 0;
		while(line.hasNext()){
			int qty = line.nextInt();
			armors.get(count).setQty(qty);
			count++;
		}
		line = new Scanner(sc.nextLine());
		while (line.hasNext()) {
			Equip temp = Utilities.findSomething(readToColon(line), equips);
			if (temp != null)
				weapons.add(temp);
		}
		line = new Scanner(sc.nextLine());
		count = 0;
		while(line.hasNext()){
			int qty = line.nextInt();
			weapons.get(count).setQty(qty);
			count++;
		}
		line = new Scanner(sc.nextLine());
		while (line.hasNext()) {
			Item temp = Utilities.findSomething(readToColon(line), this.items);
			if (temp != null)
				items.add(temp);
		}
		line = new Scanner(sc.nextLine());
		count = 0;
		while(line.hasNext()){
			int qty = line.nextInt();
			items.get(count).setQty(qty);
			count++;
		}
		line = new Scanner(sc.nextLine());
		while (line.hasNext()) {
			Action temp = Utilities.findSomething(readToColon(line),
					this.actions);
			if (temp != null)
				actions.add(temp.getName());
		}
		playerData = new Player("Maleable Man", stats, helm, armor, weapon,
				actions, new Inventory(helms, armors, weapons, items));
	}

	public void keyReleased(KeyEvent e) {
		if (state.equals(State.Map)) {
			if (e.getKeyCode() == KeyEvent.VK_LEFT && playerMap.left
					|| e.getKeyCode() == KeyEvent.VK_RIGHT && playerMap.right
					|| e.getKeyCode() == KeyEvent.VK_UP && playerMap.up
					|| e.getKeyCode() == KeyEvent.VK_DOWN && playerMap.down) {
				halt = true;
			}
		}
	}

	public void keyTyped(KeyEvent e) {

	}

	public void initialize() {
		endGame = false;
		windowWidth = 480;
		windowHeight = 480;
		actions = new ArrayList<Action>();
		items = new ArrayList<Item>();
		equips = new ArrayList<Equip>();
		animates = new ArrayList<Animation>();
		loadActions("Actions.txt");
		loadItems("Items.txt");
		loadEquips("Equips.txt");
		playerData = new Player("Maleable Man");
		playerData.equipHelm(Utilities.findSomething("Lab Helmet", equips));
		playerData.equipArmor(Utilities.findSomething("Lab Suit", equips));
		playerData.equipWeapon(Utilities.findSomething("Stone Sword", equips));
		x = 0;
		y = 0;
		invertTable = new short[256];
		for (int i = 0; i < 256; i++) {
			invertTable[i] = (short) (255 - i);
		}
		curMap = 1;
		message = "";
		enemyImages = new HashMap<String, BufferedImage>();
		enemyData = new HashMap<String, Player>();
		loadEnemies("Enemies.txt");
		maps = new Map[] {
				new Map(null, Utilities.getImage("BattleScreen.png"), null,
						null, null, null, 0), readMap("Map1"), readMap("Map2"), readMap("Map3") };
		battleWindows = readBattleWindows("Battle Windows.txt"); // 0 = title, 1
		// =
		// enemies,
		// 2 =
		// player, 3
		// = status
		Rectangle temp = battleWindows[2].getBounds();
		int xPos = ((int) (temp.getWidth() / 4) * 3) + (int) temp.getMinX();
		int yPos = (int) (temp.getHeight() / 2) + (int) temp.getMinY();
		playerMap = new Sprite("MMTopDown.png", 24, 24, 24, 8);
		playerBattle = new Sprite("MMBattleSpriteSheet.png", xPos, yPos, 25, 12);
		playerBattle.setState(5);
		Container cont = this.getParent();
		while (!(cont instanceof JFrame))
			cont = cont.getParent();
		JFrame frame = (JFrame) cont;
		frame.setIconImage(playerMap.currentImage());
		writing = false;
		menu = Utilities.getImage("Menu Border.png");
		saveWindow = Utilities.getImage("Save Window.png");
		invWindow = Utilities.getImage("InvWindow.png");
		statBar = Utilities.getImage("StatusBar.png");
		state = State.Begin;
		substate = State.None;
		buffer = new BufferedImage(windowWidth, windowHeight,
				BufferedImage.TYPE_INT_RGB);
		halt = false;
		randEncounter = 50;
		trans = 0;
		change = false;
		off = 1;
		mapMove = false;
		wasCenter = false;
		pauseCursor = 0;
		pauseOptions = new String[] { "Status", "Inventory", "Save", "Exit" };
		beginOptions = new String[] { "New", "Load", "Credits", "Exit" };
		creditLines = new String[] { "Credits", "Artwork by:", "Everett Leo",
				"Matthew Symons", "Coding by:", "Ryan Serazin",
				"Matthew Symons", "Story by:", "Matthew Symons" };
		try {
			comicbook = Font.createFont(
					Font.TRUETYPE_FONT,
					GraphicsPanel.class
					.getResourceAsStream("/resources/Comic_Book.ttf"))
					.deriveFont(24f);
		} catch (Exception e) {
			e.printStackTrace();
		}
		prevMap = 0;
		battle = null;
		beginCursor = 0;
		save1 = null;
		save2 = null;
		confirmCursor = 0;
		scrollCursor = 0;
		scrollIndex = 0;
		invCursor = 0;
		shopIndex = -1;
		animCounter = 0;
	}

	private void loadItems(String file) {
		Scanner sc = new Scanner(
				GraphicsPanel.class.getResourceAsStream("/resources/" + file));
		while (sc.hasNext()) {
			Scanner line = new Scanner(sc.nextLine());
			items.add(new Item(readToColon(line), readToColon(line),
					readToColon(line), line.nextInt(), 1));
		}
	}

	private void loadEquips(String file) {
		Scanner sc = new Scanner(
				GraphicsPanel.class.getResourceAsStream("/resources/" + file));
		while (sc.hasNext()) {
			Scanner line = new Scanner(sc.nextLine());
			String name = readToColon(line);
			int type = line.nextInt();
			equips.add(new Equip(name, (type == 0 ? Equip.Type.Helm
					: (type == 1 ? Equip.Type.Armor : Equip.Type.Weapon)),
					readToColon(line), new int[] { line.nextInt(),
				line.nextInt(), line.nextInt(), line.nextInt(),
				line.nextInt(), line.nextInt() }, line.nextInt(), 1));
		}
	}

	private void loadActions(String file) {
		Scanner sc = new Scanner(
				GraphicsPanel.class.getResourceAsStream("/resources/" + file));
		while (sc.hasNext()) {
			Scanner line = new Scanner(sc.nextLine());
			actions.add(new Action(readToColon(line), readToColon(line),
					readToColon(line), line.nextInt()));
			String name = "/resources/" + actions.get(actions.size() - 1).getName() + ".png";
			if(GraphicsPanel.class.getResource(name) != null){
				animates.add(new Animation(actions.get(actions.size() - 1).getName() + ".png",
						200, actions.get(actions.size() - 1).getName()));
			}
		}
	}

	private String readToColon(Scanner sc) {
		String temp = sc.next();
		while (!temp.endsWith(":") && sc.hasNext())
			temp += " " + sc.next();
		return temp.substring(0, temp.length() - 1);
	}

	private Polygon[] readBattleWindows(String file) {
		Scanner sc = new Scanner(
				GraphicsPanel.class.getResourceAsStream("/resources/" + file));
		Polygon[] polys = new Polygon[Integer.parseInt(sc.nextLine())];
		int inc = 0;
		while (sc.hasNext()) {
			// These are four point polygons.
			Scanner line = new Scanner(sc.nextLine());
			int[] xPoints = new int[4];
			int[] yPoints = new int[4];
			for (int i = 0; i < xPoints.length; i++) {
				xPoints[i] = line.nextInt();
				yPoints[i] = line.nextInt();
			}
			polys[inc] = new Polygon(xPoints, yPoints, 4);
			inc++;
		}
		return polys;
	}

	private Map readMap(String string) {
		InputStream is = GraphicsPanel.class.getResourceAsStream("/resources/"
				+ string + ".txt");
		BufferedImage main;
		int size = 24;
		BufferedImage[] mapData = null;
		// Read in the map box image files
		main = Utilities.getImage(string + ".png");
		mapData = new BufferedImage[main.getWidth(null) / size];
		for (int i = 0; i + size <= main.getWidth(null); i += size) {
			mapData[i / size] = main.getSubimage(i, 0, size, size);
		}
		Scanner sc = new Scanner(is);
		BufferedImage ret = null;
		int[][] map = null;
		String[] enemies = null;
		String[] equips = null;
		String[] items = null;
		HashMap<String, Integer> abilities = null;
		int warpLevel = 0;
		if (sc != null) {
			Scanner line = new Scanner(sc.nextLine());
			int width = line.nextInt();
			int height = line.nextInt();
			map = new int[width][height];
			int numEnemies = Integer.parseInt(sc.nextLine());
			enemies = new String[numEnemies];
			for (int i = 0; i < numEnemies; i++) {
				enemies[i] = sc.nextLine();
			}
			int numEquips = Integer.parseInt(sc.nextLine());
			equips = new String[numEquips];
			for (int i = 0; i < numEquips; i++) {
				equips[i] = sc.nextLine();
			}
			int numitems = Integer.parseInt(sc.nextLine());
			items = new String[numitems];
			for (int i = 0; i < numitems; i++) {
				items[i] = sc.nextLine();
			}
			int numAbils = Integer.parseInt(sc.nextLine());
			abilities = new HashMap<String, Integer>();
			for (int i = 0; i < numAbils; i++) {
				Scanner temp = new Scanner(sc.nextLine());
				abilities.put(readToColon(temp), temp.nextInt());
			}
			warpLevel = Integer.parseInt(sc.nextLine());
			ret = new BufferedImage(width * size, height * size,
					BufferedImage.TYPE_INT_RGB);
			Graphics2D g = ret.createGraphics();
			for (int i = 0; i < height; i++) {
				Scanner temp = new Scanner(sc.nextLine());
				for (int j = 0; j < width; j++) {
					int type = temp.nextInt();
					g.drawImage(mapData[type], (j * size), (i * size), null);
					map[j][i] = type;
				}
			}
		}
		return new Map(map, ret, enemies, equips, items, abilities, warpLevel);
	}

	private void loadEnemies(String file) {
		Scanner sc = new Scanner(
				GraphicsPanel.class.getResourceAsStream("/resources/" + file));
		while (sc.hasNext()) {
			Scanner line = new Scanner(sc.nextLine());
			String name = readToColon(line);
			int[] stats = new int[12];
			for (int i = 0; i < stats.length; i++) {
				stats[i] = line.nextInt();
			}
			ArrayList<String> abilities = new ArrayList<String>();
			while (line.hasNext())
				abilities.add(readToColon(line));
			BufferedImage bi = Utilities.getImage(name + ".png");
			enemyData.put(name, new Player(name, stats, null, null, null,
					abilities, new Inventory()));
			enemyImages.put(name, bi);
		}
	}

	public void update() {
		if (state.equals(State.Map)) {// Moving on the world map
			String dir = (playerMap.left ? "l" : (playerMap.right ? "r"
					: (playerMap.down ? "d" : (playerMap.up ? "u" : "n"))));
			wasCenter = (x % 24 == 0 && y % 24 == 0 && playerMap.x % 24 == 0
					&& playerMap.y % 24 == 0 ? true : false);
			if (!dir.equals("n")) { // we are definitely trying to move
				if (((dir.equals("l") && (playerMap.x / 24) > 15)
						|| (dir.equals("r") && (playerMap.x / 24) < 4)
						|| (dir.equals("u") && (playerMap.y / 24) > 15) || (dir
								.equals("d") && (playerMap.y / 24) < 4)) && !mapMove) {
					// If too close to the top, move him instead
					playerMap.move();
					playerMove = true;
				} else if (dir.equals("l") && x != 0 && !playerMove)
					x -= playerMap.speed;
				else if (dir.equals("r")
						&& x != maps[curMap].image().getWidth() - windowWidth
						&& !playerMove)
					x += playerMap.speed;
				else if ((dir.equals("u") && y != 0 && !playerMove))
					y -= playerMap.speed;
				else if (dir.equals("d")
						&& y != maps[curMap].image().getHeight() - windowHeight
						&& !playerMove)
					y += playerMap.speed;
				else if (!mapMove) {
					playerMove = true;
					playerMap.move();
				}
				if (!playerMove)
					mapMove = true;
				change = true;
				if (dir.equals("l"))
					playerMap.setState(off == 1 ? 10 : 11);
				else if (dir.equals("r"))
					playerMap.setState(off == 1 ? 7 : 8);
				else if (dir.equals("u"))
					playerMap.setState(off == 1 ? 4 : 5);
				else if (dir.equals("d"))
					playerMap.setState(off == 1 ? 1 : 2);
				off *= -1;
			}
		} else if (state.equals(State.Transition)) {
			trans += 1;
			if (state.equals(State.Transition) && trans == 5) {
				if(endGame) {
					state = State.GameWon;
				}
				else{
					state = State.PostTransition;
					int temp = prevMap;
					prevMap = curMap;
					curMap = temp;
					if (curMap != 0)
						battle = null;
				}
			}
		} else if (state.equals(State.PostTransition)) {
			trans -= 1;
			if (state.equals(State.PostTransition) && trans == 0) {
				if (curMap == 0) {
					animCounter = 4;
					state = State.BattleForward;
					playerBattle.setState(5);
					playerBattle.left = true;
					substate = State.BattleMenu;
				} else
					state = State.Map;
			}
		} else if (state.equals(State.Save) || (state.equals(State.Load))) {
			if (!writing) {
				if (save1 == null)
					save1 = new File("MMsav1.sav");
				if (save2 == null)
					save2 = new File("MMsav2.sav");
				if (!save1.exists())
					save1 = null;
				if (!save2.exists())
					save2 = null;
			}
		} else if (state.equals(State.BattleForward)
				|| state.equals(State.BattleBackward)) {
			animCounter--;
			if (animCounter == 0) {
				if (substate.equals(State.BattleQueue))
					battle.recycle();
				animCounter = 4;
				off = 1;
				playerBattle.left = false;
				playerBattle.right = false;
				playerBattle.setState(playerBattle.getState() + off);
				state = substate;
				substate = State.None;
			} else {
				off *= -1;
				playerBattle.setState(playerBattle.getState() + off);
				playerBattle.move();
			}
		} else if (state.equals(State.BattleQueue)) {
			if (battle.nextTurn()) {
				Player play = battle.currentTurn();
				if (play.getName().equals("Maleable Man")) {
					if (battle.currentAction().equals("Run")) {
						int chance = battle.processCommand(battle
								.playerAction().getCommand(), playerData,
								playerData);
						if (chance == 1) {
							substate = State.Transition;
							message = "Ran Away";
						} else {
							substate = State.BattleQueue;
							message = "Couldn't Run";
						}
						state = State.BattleMessage;
						animCounter = 6;
					} 
					else {
						animCounter = 4;
						substate = State.BattlePlayerAttack;
						state = State.BattleForward;
						playerBattle.setState(5);
						playerBattle.left = true;
					}
				} else {
					if (battle.currentTurn().getCurHp() > 0) {
						animCounter = 4;
						state = State.BattleEnemyAttack;
					}
				}
			} else {
				animCounter = 4;
				state = State.BattleForward;
				playerBattle.setState(5);
				playerBattle.left = true;
				substate = State.BattleMenu;
			}
		} else if (state.equals(State.BattlePlayerAttack)) {
			animCounter--;
			off *= -1;
			if (animCounter == 0) {
				off = 1;
				animCounter = 4;
				if (battle.currentAction().equals("Attack")) {
					state = State.BattleEnemyDamage;
				} else {
					animCounter = 6;
					state = State.BattleMessage;
					substate = State.BattlePlayerAnimation;
					message = battle.currentAction();
				}
			}
		} else if (state.equals(State.BattleEnemyAttack)) {
			animCounter--;
			off *= -1;
			if (animCounter == 0) {
				off = 1;
				animCounter = 4;
				if (battle.currentAction().equals("Attack")) {
					state = State.BattlePlayerDamage;
				} else {
					animCounter = 6;
					state = State.BattleMessage;
					substate = State.BattleEnemyAnimation;
					message = battle.currentAction();
				}
			}
		} else if (state.equals(State.BattlePlayerDamage)
				|| state.equals(State.BattleEnemyDamage)) {
			animCounter--;
			off *= -1;
			if (animCounter == 0) {
				off = 1;
				animCounter = 6;
				state = state.equals(State.BattlePlayerDamage) ? State.BattlePlayerNumber
						: State.BattleEnemyNumber;
			}
		} else if (state.equals(State.BattlePlayerNumber)) {
			animCounter--;
			if (animCounter == 0) {
				Action a = Utilities.findSomething(battle.currentAction(),
						actions);
				int damage = battle.processCommand(a.getCommand(),
						battle.currentTurn(), playerData);
				playerData
				.setCurHp(Math.max(playerData.getCurHp() - damage, 0));
				state = State.BattlePostAttack;
			}
		} else if (state.equals(State.BattleEnemyNumber)) {
			animCounter--;
			if (animCounter == 0) {
				Action a = battle.playerAction();
				boolean dead = false;
				if(a.getCommand().contains("damage")){
					for (Player enm : battle.getTarget()) {
						int damage = battle.processCommand(a.getCommand(),
								playerData, enm);
						enm.setCurHp(Math.max(enm.getCurHp() - damage, 0));
					}
				}
				else{
					for (Player enm : battle.getTarget()) {
						int heal = battle.processCommand(a.getCommand(),
								playerData, enm);
						if(a.getCommand().contains("replenish"))
							enm.setCurMp(enm.getCurMp() + heal);
						else
							enm.setCurHp(enm.getCurHp() + heal);
					}
				}
				animCounter = 4;
				if (dead) {
					state = State.BattleEnemyDeath;
				} else {
					substate = State.BattlePostAttack;
					state = State.BattleBackward;
					playerBattle.setState(5);
					playerBattle.right = true;
				}
			}
		} else if (state.equals(State.BattlePostAttack)) {
			animCounter = 4;
			if (battle.numEnemiesAlive() == 0) {
				animCounter += 2;
				victoryIndex = 10;
				message = "Gained " + battle.getGoldWon() + " gold";
				state = State.BattleVictory;
			} else if (playerData.getCurHp() == 0) {
				state = State.BattlePlayerDeath;
			} else {
				state = State.BattleQueue;
			}
		} else if (state.equals(State.BattleMessage)) {
			animCounter--;
			if (animCounter == 0) {
				animCounter = 4;
				state = substate;
				substate = State.None;
				message = "";
			}
		} else if (state.equals(State.BattleEnemyAnimation) ||
				state.equals(State.BattlePlayerAnimation)) {
			animCounter--;
			if (animCounter == 0) {
				int mc = 0;
				if(state.equals(State.BattlePlayerAnimation))
					mc = battle.playerAction().getManaCost();
				else
					mc = Utilities.findSomething(battle.currentAction(), actions).getManaCost();
				battle.currentTurn().setCurMp(battle.currentTurn().getCurMp() - mc);
				animCounter = 4;
				state = (state.equals(State.BattleEnemyAnimation)) ?
						State.BattlePlayerDamage : State.BattleEnemyDamage;
			}
		} else if (state.equals(State.BattlePlayerDeath)) {
			trans += 1;
			if (trans == 5) {
				trans = 0;
				state = State.GameOver;
			}
		} else if (state.equals(State.BattlePlayerDeath)) {
			animCounter--;
			if (animCounter == 0) {
				animCounter = 4;
				substate = State.BattlePostAttack;
				state = State.BattleBackward;
				playerBattle.setState(5);
				playerBattle.right = true;
			}
		}
		else if(state.equals(State.BattleVictory)){
			off *= -1;
			if(animCounter == 0){
				boolean wait = true;
				victoryIndex--;
				animCounter = 6;
				if(victoryIndex == 9){
					playerData.setGold(playerData.getGold() + battle.getGoldWon());
					message = "Gained " + battle.getExpWon() + " exp";
					int curExp = playerData.getExp();
					if(curExp + battle.getExpWon() >= nextLevelExp()){
						playerData.setExp((curExp + battle.getExpWon()) - nextLevelExp());
						playerData.levelUp();
						message += ": Level Up!";
					}
					else
						playerData.setExp(curExp + battle.getExpWon());
				}
				else if(victoryIndex == 8){
					if(message.contains("Level")){
						message = "Hp raised by " + battle.statRaiseIfLevel()[0];
						playerData.setHp(playerData.getBaseHp() + battle.statRaiseIfLevel()[0]);
					}
					else{
						state = State.Transition;
					}
				}
				else if(victoryIndex == 7 && battle.statRaiseIfLevel()[1] != 0){
					message = "Mp raised by " + battle.statRaiseIfLevel()[1];
					playerData.setMp(playerData.getBaseMp() + battle.statRaiseIfLevel()[1]);
					wait = false;
				}
				else if(victoryIndex == 6 && battle.statRaiseIfLevel()[2] != 0){
					message = "Def raised by " + battle.statRaiseIfLevel()[2];
					playerData.setDef(playerData.getBaseDef() + battle.statRaiseIfLevel()[2]);
					wait = false;
				}
				else if(victoryIndex == 5 && battle.statRaiseIfLevel()[3] != 0){
					message = "Mdef raised by " + battle.statRaiseIfLevel()[3];
					playerData.setMdef(playerData.getBaseMdef() + battle.statRaiseIfLevel()[3]);
					wait = false;
				}
				else if(victoryIndex == 4 && battle.statRaiseIfLevel()[4] != 0){
					message = "Str raised by " + battle.statRaiseIfLevel()[4];
					playerData.setStr(playerData.getBaseStr() + battle.statRaiseIfLevel()[4]);
					wait = false;
				}
				else if(victoryIndex == 3 && battle.statRaiseIfLevel()[5] != 0){
					message = "Int raised by " + battle.statRaiseIfLevel()[5];
					playerData.setInt(playerData.getBaseInt() + battle.statRaiseIfLevel()[5]);
					wait = false;
				}
				else if(victoryIndex == 2 && battle.statRaiseIfLevel()[6] != 0){
					message = "Speed raised by " + battle.statRaiseIfLevel()[6];
					playerData.setSpeed(playerData.getSpeed() + battle.statRaiseIfLevel()[6]);
					wait = false;
				}
				else if(victoryIndex == 1){
					Random r = new Random();
					int index1 = r.nextInt(battle.statRaiseIfLevel().length);
					int index2 = r.nextInt(battle.statRaiseIfLevel().length);
					while(index1 == index2){
						index2 = r.nextInt(battle.statRaiseIfLevel().length);
					}
					message = swapSkills(index1, index2);
				}
				else if(victoryIndex == 0)
					state = State.Transition;
				if(victoryIndex != 0 && !wait){
					animCounter = 0;
				}
			}
		}
	}

	private String swapSkills(int index1, int index2) {
		if(index1 == 0){
			int temp = playerData.getBaseHp();
			if(index2 == 1){
				playerData.setHp(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Hp with Mp";
			}
			else if(index2 == 2){
				playerData.setHp(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Hp with Def";
			}
			else if(index2 == 3){
				playerData.setHp(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Hp with Mdef";
			}
			else if(index2 == 4){
				playerData.setHp(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Hp with Str";
			}
			else if(index2 == 5){
				playerData.setHp(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Hp with Int";
			}
			else if(index2 == 6){
				playerData.setHp(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Hp with Speed";
			}
		}
		else if(index1 == 1){
			int temp = playerData.getBaseMp();
			if(index2 == 0){
				playerData.setMp(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Mp with Hp";
			}
			else if(index2 == 2){
				playerData.setMp(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Mp with Def";
			}
			else if(index2 == 3){
				playerData.setMp(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Mp with Mdef";
			}
			else if(index2 == 4){
				playerData.setMp(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Mp with Str";
			}
			else if(index2 == 5){
				playerData.setMp(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Mp with Int";
			}
			else if(index2 == 6){
				playerData.setMp(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Mp with Speed";
			}
		}
		else if(index1 == 2){
			int temp = playerData.getBaseDef();
			if(index2 == 0){
				playerData.setDef(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Def with Hp";
			}
			else if(index2 == 1){
				playerData.setDef(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Def with Mp";
			}
			else if(index2 == 3){
				playerData.setDef(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Def with Mdef";
			}
			else if(index2 == 4){
				playerData.setDef(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Def with Str";
			}
			else if(index2 == 5){
				playerData.setDef(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Def with Int";
			}
			else if(index2 == 6){
				playerData.setDef(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Def with Speed";
			}
		}
		else if(index1 == 3){
			int temp = playerData.getBaseMdef();
			if(index2 == 0){
				playerData.setMdef(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Mdef with Hp";
			}
			else if(index2 == 1){
				playerData.setMdef(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Mdef with Mp";
			}
			else if(index2 == 2){
				playerData.setMdef(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Mdef with Def";
			}
			else if(index2 == 4){
				playerData.setMdef(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Mdef with Str";
			}
			else if(index2 == 5){
				playerData.setMdef(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Mdef with Int";
			}
			else if(index2 == 6){
				playerData.setMdef(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Mdef with Speed";
			}
		}
		else if(index1 == 4){
			int temp = playerData.getBaseStr();
			if(index2 == 0){
				playerData.setStr(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Str with Hp";
			}
			else if(index2 == 1){
				playerData.setStr(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Str with Mp";
			}
			else if(index2 == 2){
				playerData.setStr(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Str with Def";
			}
			else if(index2 == 3){
				playerData.setStr(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Str with Mdef";
			}
			else if(index2 == 5){
				playerData.setStr(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Str with Int";
			}
			else if(index2 == 6){
				playerData.setStr(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Str with Speed";
			}
		}
		else if(index1 == 5){
			int temp = playerData.getBaseInt();
			if(index2 == 0){
				playerData.setInt(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Int with Hp";
			}
			else if(index2 == 1){
				playerData.setInt(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Int with Mp";
			}
			else if(index2 == 2){
				playerData.setInt(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Int with Def";
			}
			else if(index2 == 3){
				playerData.setInt(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Int with Mdef";
			}
			else if(index2 == 4){
				playerData.setInt(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Int with Str";
			}
			else if(index2 == 6){
				playerData.setInt(playerData.getSpeed());
				playerData.setSpeed(temp);
				return "Swapped Int with Speed";
			}
		}
		else if(index1 == 6){
			int temp = playerData.getSpeed();
			if(index2 == 0){
				playerData.setSpeed(playerData.getBaseHp());
				playerData.setHp(temp);
				return "Swapped Speed with Hp";
			}
			else if(index2 == 1){
				playerData.setSpeed(playerData.getBaseMp());
				playerData.setMp(temp);
				return "Swapped Speed with Mp";
			}
			else if(index2 == 2){
				playerData.setSpeed(playerData.getBaseDef());
				playerData.setDef(temp);
				return "Swapped Speed with Def";
			}
			else if(index2 == 3){
				playerData.setSpeed(playerData.getBaseMdef());
				playerData.setMdef(temp);
				return "Swapped Speed with Mdef";
			}
			else if(index2 == 4){
				playerData.setSpeed(playerData.getBaseStr());
				playerData.setStr(temp);
				return "Swapped Speed with Str";
			}
			else if(index2 == 5){
				playerData.setSpeed(playerData.getBaseInt());
				playerData.setInt(temp);
				return "Swapped Speed with Int";
			}
		}
		return "";
	}

	public void checkCollisions() {
		if (state.equals(State.Map)) {
			if (change) {
				// Rule out any edges
				if (x < 0) {
					x += playerMap.speed;
					change = false;
				} else if (x > maps[curMap].image().getWidth() - windowWidth) {
					x -= playerMap.speed;
					change = false;
				} else if (y < 0) {
					y += playerMap.speed;
					change = false;
				} else if (y > maps[curMap].image().getHeight() - windowHeight) {
					y -= playerMap.speed;
					change = false;
				} else if (playerMap.x < 0) {
					playerMap.x += playerMap.speed;
					change = false;
				} else if (playerMap.x > windowWidth - 24) {
					playerMap.x -= playerMap.speed;
					change = false;
				} else if (playerMap.y < 0) {
					playerMap.y += playerMap.speed;
					change = false;
				} else if (playerMap.y > windowHeight - 24) {
					playerMap.y -= playerMap.speed;
					change = false;
				} else if (wasCenter) {
					// We know the direction is not an edge.
					// See if there is a foreign object in the way
					// we used speed * 2 because this will always be the first
					// check on a move.
					int mapX = 0;
					int mapY = 0;
					if (playerMap.left) {
						mapX = (mapMove ? ((x - (playerMap.speed * 2)) / 24)
								+ (playerMap.x / 24) : (x / 24)
								+ ((playerMap.x - (playerMap.speed * 2)) / 24));
						mapY = (y / 24) + (playerMap.y / 24);
					} else if (playerMap.right) {
						mapX = (mapMove ? ((x + (playerMap.speed * 2)) / 24)
								+ (playerMap.x / 24) : (x / 24)
								+ ((playerMap.x + (playerMap.speed * 2)) / 24));
						mapY = (y / 24) + (playerMap.y / 24);
					} else if (playerMap.up) {
						mapX = (x / 24) + (playerMap.x / 24);
						mapY = (mapMove ? ((y - (playerMap.speed * 2)) / 24)
								+ (playerMap.y / 24) : (y / 24)
								+ ((playerMap.y - (playerMap.speed * 2)) / 24));
					} else if (playerMap.down) {
						mapX = (x / 24) + (playerMap.x / 24);
						mapY = (mapMove ? ((y + (playerMap.speed * 2)) / 24)
								+ (playerMap.y / 24) : (y / 24)
								+ ((playerMap.y + (playerMap.speed * 2)) / 24));
					}
					if (maps[curMap].typeAt(mapX, mapY) != 0) {
						if (playerMap.left) {
							if (mapMove)
								x += playerMap.speed;
							else
								playerMap.x += playerMap.speed;
						} else if (playerMap.right) {
							if (mapMove)
								x -= playerMap.speed;
							else
								playerMap.x -= playerMap.speed;
						} else if (playerMap.up) {
							if (mapMove)
								y += playerMap.speed;
							else
								playerMap.y += playerMap.speed;
						} else if (playerMap.down) {
							if (mapMove)
								y -= playerMap.speed;
							else
								playerMap.y -= playerMap.speed;
						}
						change = false;
					}
				}
			}
		} else if (state.equals(State.Pause)) {
			if (pauseCursor < 0)
				pauseCursor = pauseOptions.length - 1;
			else if (pauseCursor >= pauseOptions.length)
				pauseCursor = 0;
		} else if (state.equals(State.Begin)) {
			if (beginCursor < 0)
				beginCursor = beginOptions.length - 1;
			else if (beginCursor >= beginOptions.length)
				beginCursor = 0;
		} else if (state.equals(State.Save) || state.equals(State.Load)) {
			if (saveCursor < 0)
				saveCursor = 1;
			else if (saveCursor > 1)
				saveCursor = 0;
		} else if (state.equals(State.Confirm)) {
			if (confirmCursor < 0)
				confirmCursor = 1;
			else if (confirmCursor > 1)
				confirmCursor = 0;
		} else if (state.equals(State.Status) || state.equals(State.BattleMenu)) {
			if (scrollCursor < 0) {
				scrollCursor = 0;
				if (scrollIndex > 0)
					scrollIndex--;
			} else if (scrollCursor > 3) {
				scrollCursor = 3;
				int lim = playerData.getActions().size();
				if(state.equals(State.BattleMenu))
					lim += 2;
				if (scrollIndex + scrollCursor < lim)
					scrollIndex++;
			}
		} else if (state.equals(State.BattleCursor)) {
			if (invCursor < 0)
				invCursor = battle.getBaddies().size();
			else if (invCursor >= battle.getBaddies().size())
				invCursor = 0;
		}
		else if(state.equals(State.BattleInventory)){
			if (battleCursor < 0) {
				battleCursor = 0;
				if (battleIndex > 0)
					battleIndex--;
			} else if (battleCursor > 10) {
				battleCursor = 10;
				if (scrollCursor + scrollIndex < playerData.getInv().items.size())
					scrollIndex++;
			}
		}
		else if (state.equals(State.Inventory)) {
			if (scrollCursor < 0) {
				scrollCursor = 0;
				if (scrollIndex > 0)
					scrollIndex--;
			} else if (scrollCursor > 11) {
				scrollCursor = 11;
				int limit = 0;
				if (invCursor == 0)
					limit = playerData.getInv().helms.size();
				else if (invCursor == 1)
					limit = playerData.getInv().armors.size();
				else if (invCursor == 2)
					limit = playerData.getInv().weapons.size();
				else if (invCursor == 3)
					limit = playerData.getInv().items.size();
				if (scrollCursor + scrollIndex < limit)
					scrollIndex++;
			}
			if (invCursor < 0)
				invCursor = 3;
			else if (invCursor > 3)
				invCursor = 0;
		} else if (state.equals(State.Shop)) {
			if (scrollCursor < 0) {
				scrollCursor = 0;
				if (scrollIndex > 0)
					scrollIndex--;
			} else if (scrollCursor > 10) {
				scrollCursor = 10;
				int limit = 0;
				if (invCursor == 0) {
					if (shopIndex == 1)
						limit = playerData.getInv().helms.size();
					else
						limit = maps[curMap].equipsForSale().length;
				} else if (invCursor == 1) {
					if (shopIndex == 1)
						limit = playerData.getInv().armors.size();
					else
						limit = maps[curMap].itemsForSale().length;
				} else if (invCursor == 2) {
					if (shopIndex == 1)
						limit = playerData.getInv().weapons.size();
					else
						limit = maps[curMap].getAbilities().length;
				} else if (invCursor == 3 && shopIndex == 1)
					limit = playerData.getInv().items.size();
				if (scrollCursor + scrollIndex < limit)
					scrollIndex++;
			}
			if (invCursor < 0 && shopIndex == 0)
				invCursor = 2;
			else if (invCursor < 0 && shopIndex == 1)
				invCursor = 3;
			else if (invCursor < 0 && shopIndex == -1)
				invCursor = 1;
			else if (invCursor > 2 && shopIndex == 0)
				invCursor = 0;
			else if (invCursor > 3 && shopIndex == 1)
				invCursor = 0;
			else if (invCursor > 1 && shopIndex == -1)
				invCursor = 0;
		}
	}

	public void drawBuffer(State curState) {
		Graphics2D g = buffer.createGraphics();
		g.setColor(Color.white);
		g.setFont(comicbook);
		if (curState.equals(State.Map) || curState.equals(State.Pause)
				|| (curState.equals(State.Transition) && curMap != 0)
				|| (curState.equals(State.PostTransition) && curMap != 0)
				|| curState.equals(State.Status)
				|| curState.equals(State.Inventory)
				|| curState.equals(State.Shop)) {
			g.drawImage(maps[curMap].image(), 0, 0, windowWidth,
					buffer.getHeight(), x, y, x + windowWidth,
					y + buffer.getHeight(), null);
			g.drawImage(playerMap.currentImage(), playerMap.x, playerMap.y,
					null);
			if (curState.equals(State.Transition)
					|| curState.equals(State.PostTransition)) {
				for (int i = 0; i < windowWidth; i++) {
					for (int j = 0; j < windowHeight; j++) {
						buffer.setRGB(i, j, fade(buffer.getRGB(i, j)));
					}
				}
			} else if (curState.equals(State.Pause)) {
				int drawX = (windowWidth / 2) - (menu.getWidth() / 2);
				int drawY = (windowHeight / 2) - (menu.getHeight() / 2);
				g.drawImage(menu, drawX, drawY, null);
				for (int i = 0; i < menu.getWidth(); i++) {
					for (int j = 0; j < menu.getHeight(); j++) {
						Color temp = new Color(buffer.getRGB(drawX + i, drawY
								+ j));
						Color cur = new Color(menu.getRGB(i, j));
						if (cur.getRGB() == -16777216 && i >= 5
								&& i <= menu.getWidth() - 5 && j >= 5
								&& j <= menu.getHeight() - 5) {
							buffer.setRGB(
									drawX + i,
									drawY + j,
									new Color(temp.getRed() / 2, temp
											.getGreen() / 2, temp.getBlue() / 2)
									.getRGB());
						}
					}
				}
				g.setFont(comicbook);
				int i = 0;
				int cursor = pauseCursor;
				for (String str : pauseOptions) {
					int length = (int) g.getFontMetrics().stringWidth(str);
					int dispX = (windowWidth / 2) - (length / 2);
					int height = g.getFontMetrics().getHeight();
					int dispY = drawY + 5 + i * height + ((height * 3) / 4);
					g.drawString(str, dispX, dispY);
					if (cursor == i && cursor >= 0) {
						int drawFactor = (int) g.getFontMetrics()
								.getStringBounds(str, g).getBounds()
								.getCenterY();
						g.setColor(Color.white);
						g.fillPolygon(new int[] { drawX + 10, drawX + 20,
								drawX + 10 }, new int[] {
								dispY + drawFactor - 10, dispY + drawFactor,
								dispY + drawFactor + 10 }, 3);
						g.setColor(Color.black);
						g.drawPolygon(new int[] { drawX + 10, drawX + 20,
								drawX + 10 }, new int[] {
								dispY + drawFactor - 10, dispY + drawFactor,
								dispY + drawFactor + 10 }, 3);
						g.setColor(Color.white);
					}
					i++;
				}
			} else if (curState.equals(State.Status)) {
				int drawX = (windowWidth / 2) - (invWindow.getWidth() / 2);
				int drawY = (windowHeight / 2) - (invWindow.getHeight() / 2);
				g.drawImage(invWindow, drawX, drawY, null);
				for (int i = 0; i < invWindow.getWidth(); i++) {
					for (int j = 0; j < invWindow.getHeight(); j++) {
						Color temp = new Color(buffer.getRGB(drawX + i, drawY
								+ j));
						Color cur = new Color(invWindow.getRGB(i, j));
						if (cur.getRGB() == -16777216 && i >= 5
								&& i <= invWindow.getWidth() - 5 && j >= 5
								&& j <= invWindow.getHeight() - 5) {
							buffer.setRGB(
									drawX + i,
									drawY + j,
									new Color(temp.getRed() / 2, temp
											.getGreen() / 2, temp.getBlue() / 2)
									.getRGB());
						}
					}
				}
				g.setFont(comicbook);
				String[] playerDat = new String[] {
						"Str: " + playerData.getStr(),
						"Int: " + playerData.getInt(),
						"Def: " + playerData.getDef(),
						"Mdef: " + playerData.getMdef(),
						"Speed: " + playerData.getSpeed(), "Helm:",
						"  " + playerData.getHelm().getName(), "Armor:",
						"  " + playerData.getArmor().getName(), "Weapon:",
						"  " + playerData.getWeapon().getName() };
				int font = 15;
				int height = 0;
				for (int i = 0; i < playerDat.length; i++) {
					while (g.getFontMetrics(comicbook.deriveFont(font * 1f))
							.stringWidth(playerDat[4]) > (invWindow.getWidth() / 3))
						font--;
					if (i == 0)
						height += g.getFontMetrics().getHeight();
					g.setFont(comicbook.deriveFont(font * 1f));
					int tempX = drawX + 7;
					g.drawString(playerDat[i], tempX, drawY + height);
					height += g.getFontMetrics().getHeight();
					font = 15;
				}
				g.setFont(comicbook);
				int halfX = drawX + (invWindow.getWidth() / 2);
				String level = "Level: " + playerData.getLevel();
				String gold = "Gold: " + playerData.getGold();
				font = comicbook.getSize();
				while (g.getFontMetrics(comicbook.deriveFont(font * 1f))
						.stringWidth(gold) > (invWindow.getWidth() / 3))
					font--;
				g.setFont(comicbook.deriveFont(font * 1f));
				g.drawString(level,
						halfX - (g.getFontMetrics().stringWidth(level) / 2),
						drawY + g.getFontMetrics().getHeight());
				g.drawString(gold, halfX
						- (g.getFontMetrics().stringWidth(gold) / 2),
						(int) (drawY + (g.getFontMetrics().getHeight() * 2.3)));
				int levelY = drawY + g.getFontMetrics().getHeight();
				int tempY = drawY + (g.getFontMetrics().getHeight() * 3);
				g.drawImage(statBar, halfX - (statBar.getWidth() / 2), tempY,
						null);
				g.setColor(Color.red);
				g.fillRect(halfX - (statBar.getWidth() / 2) + 5, tempY + 5,
						(playerData.getCurHp() * 40) / playerData.getHp(), 5);
				tempY += statBar.getHeight();
				g.setColor(Color.white);
				String hp = "Hp: " + playerData.getCurHp() + "/"
						+ playerData.getHp();
				String mp = "Mp: " + playerData.getCurMp() + "/"
						+ playerData.getMp();
				String exp = "Exp: " + playerData.getExp() + "/"
						+ nextLevelExp();
				font = comicbook.getSize();
				while (g.getFontMetrics(comicbook.deriveFont(font * 1f))
						.stringWidth(hp) > (invWindow.getWidth() / 3))
					font--;
				g.setFont(comicbook.deriveFont(font * 1f));
				tempY += g.getFontMetrics().getHeight();
				g.drawString(hp, halfX
						- (g.getFontMetrics().stringWidth(hp) / 2), tempY);
				font = comicbook.getSize();
				while (g.getFontMetrics(comicbook.deriveFont(font * 1f))
						.stringWidth(mp) > (invWindow.getWidth() / 3))
					font--;
				g.setFont(comicbook.deriveFont(font * 1f));
				int tempX = drawX + invWindow.getWidth() - 7
						- g.getFontMetrics().stringWidth(mp);
				g.drawString(mp, tempX, tempY);
				tempY -= g.getFontMetrics().getHeight();
				g.drawImage(statBar, tempX + (statBar.getWidth() / 2), tempY
						- statBar.getHeight(), null);
				g.setColor(Color.blue);
				g.fillRect(tempX + (statBar.getWidth() / 2) + 5, tempY
						- statBar.getHeight() + 5, (playerData.getCurMp() * 40)
						/ playerData.getMp(), 5);
				g.setColor(Color.white);
				font = comicbook.getSize();
				while (g.getFontMetrics(comicbook.deriveFont(font * 1f))
						.stringWidth(exp) > (invWindow.getWidth() / 3))
					font--;
				g.setFont(comicbook.deriveFont(font * 1f));
				tempX = drawX + invWindow.getWidth() - 7
						- g.getFontMetrics().stringWidth(exp);
				g.drawImage(statBar, tempX + (statBar.getWidth() / 2), levelY,
						null);
				g.setColor(new Color(255, 215, 0)); // Gold color
				g.fillRect(tempX + (statBar.getWidth() / 2) + 5, levelY + 5,
						(playerData.getExp() * 40) / nextLevelExp(), 5);
				g.setColor(Color.white);
				levelY += statBar.getHeight() + g.getFontMetrics().getHeight();
				g.drawString(exp, tempX, levelY);
				g.setFont(comicbook);
				int actionX = drawX + (invWindow.getWidth() / 2)
						- (g.getFontMetrics().stringWidth("Actions") / 2);
				g.drawString("Actions", actionX, drawY
						+ (invWindow.getHeight() / 2));
				int longest = -1;
				int length = 0;
				if (playerData.getActions().size() > 0) {
					for (int i = 0; i < playerData.getActions().size(); i++) {
						int len = g.getFontMetrics().stringWidth(
								playerData.getActions().get(i));
						if (len > length) {
							longest = i;
							length = len;
						}
					}
				}
				if (longest == -1)
					length = g.getFontMetrics().stringWidth("None");
				font = comicbook.getSize();
				while (length >= invWindow.getWidth() / 3 && longest != -1) {
					font--;
					length = g.getFontMetrics(comicbook.deriveFont(font * 1f))
							.stringWidth(playerData.getActions().get(longest));
				}
				g.setFont(comicbook.deriveFont(font * 1f));
				int actionYTop = drawY + invWindow.getHeight() - 7
						- ((g.getFontMetrics().getHeight() + 3) * 4);
				int yInc = actionYTop;
				for (int i = 0; i < 4; i++) {
					String name = "None";
					String desc = "No Action learned.";
					if (i + scrollIndex < playerData.getActions().size())
						name = playerData.getActions().get(i + scrollIndex);
					g.setColor(Color.gray);
					if (!name.equals("None")) {
						Action temp = Utilities.findSomething(name, actions);
						desc = temp.getDescription();
						if (temp.getCommand().startsWith("recover")
								&& temp.getManaCost() <= playerData.getCurMp())
							g.setColor(Color.white);
					}
					g.drawString(name, drawX + (invWindow.getWidth() / 3)
							- g.getFontMetrics().stringWidth(name), yInc);
					g.setColor(Color.white);
					if (scrollCursor == i) {
						g.drawRect(drawX + (invWindow.getWidth() / 3)
								- g.getFontMetrics().stringWidth(name) - 1,
								yInc - g.getFontMetrics().getHeight() + 3,
								g.getFontMetrics().stringWidth(name) + 2, g
								.getFontMetrics().getHeight());
						// Draw desc
						int prevFont = g.getFont().getSize();
						g.setFont(comicbook.deriveFont(16 * 1f));
						while (desc.length() > 0) {
							String temp = desc;
							desc = "";
							while (temp.length() > 0
									&& g.getFontMetrics().stringWidth(temp) > (drawX + invWindow
											.getWidth()) - actionX) {
								int index = temp.lastIndexOf(" ");
								desc = temp.substring(index, temp.length())
										+ desc;
								temp = temp.substring(0, index);
							}
							g.drawString(temp, actionX, actionYTop);
							actionYTop += g.getFontMetrics().getHeight();
						}
						g.setFont(comicbook.deriveFont(prevFont * 1f));
					}
					yInc += 3 + g.getFontMetrics().getHeight();
				}
			} else if (curState.equals(State.Inventory)) {
				int drawX = (windowWidth / 2) - (invWindow.getWidth() / 2);
				int drawY = (windowHeight / 2) - (invWindow.getHeight() / 2);
				g.drawImage(invWindow, drawX, drawY, null);
				for (int i = 0; i < invWindow.getWidth(); i++) {
					for (int j = 0; j < invWindow.getHeight(); j++) {
						Color temp = new Color(buffer.getRGB(drawX + i, drawY
								+ j));
						Color cur = new Color(invWindow.getRGB(i, j));
						if (cur.getRGB() == -16777216 && i >= 5
								&& i <= invWindow.getWidth() - 5 && j >= 5
								&& j <= invWindow.getHeight() - 5) {
							buffer.setRGB(
									drawX + i,
									drawY + j,
									new Color(temp.getRed() / 2, temp
											.getGreen() / 2, temp.getBlue() / 2)
									.getRGB());
						}
					}
				}
				g.setFont(comicbook);
				g.setColor(Color.black);
				g.drawLine(drawX + 5, drawY + 5
						+ g.getFontMetrics().getHeight() + 6,
						drawX + invWindow.getWidth() - 5, drawY + 5
						+ g.getFontMetrics().getHeight() + 6);
				g.setColor(Color.white);
				String[] top = new String[] { "Equips", "Armors", "Weapons",
				"Items" };
				int stringWidths = 0;
				for (int i = 0; i < top.length; i++) {
					stringWidths += g.getFontMetrics().stringWidth(top[i]);
				}
				int spacing = (invWindow.getWidth() - 12 - stringWidths) / 4;
				stringWidths = 0;
				int yPos = 0;
				for (int i = 0; i < top.length; i++) {
					int xPos = drawX + 1 + (i * spacing) + stringWidths + 6;
					yPos = drawY + g.getFontMetrics().getHeight() + 5 + 3;
					g.drawString(top[i], xPos, yPos);
					if (i == invCursor) {
						g.drawRect(xPos - 1, yPos
								- g.getFontMetrics().getHeight() - 1, g
								.getFontMetrics().stringWidth(top[i]) + 2, g
								.getFontMetrics().getHeight() + 2);
					}
					xPos += g.getFontMetrics().stringWidth(top[i]);
					if (i != top.length - 1) {
						g.setColor(Color.black);
						g.drawLine(xPos + (spacing / 2), drawY + 5, xPos
								+ (spacing / 2), yPos + 3);
						g.setColor(Color.white);
					}
					stringWidths += g.getFontMetrics().stringWidth(top[i]);
				}
				ArrayList<? extends Comparable<? extends Object>> inv = (invCursor == 0 ? playerData
						.getInv().helms
						: (invCursor == 1 ? playerData.getInv().armors
								: (invCursor == 2 ? playerData.getInv().weapons
										: playerData.getInv().items)));
				int leftX = drawX + 6;
				int rightX = drawX + ((invWindow.getWidth() * 7) / 8);
				g.setFont(comicbook.deriveFont(15f));
				int yInc = yPos + 2 + g.getFontMetrics().getHeight();
				g.drawString("Gold: " + playerData.getGold(), leftX, yInc);
				yInc += g.getFontMetrics().getHeight() + 2;
				g.drawString("Name", leftX, yInc);
				g.drawString("Qty",
						rightX - g.getFontMetrics().stringWidth("Qty"), yInc);
				yInc += g.getFontMetrics().getHeight() + 2;
				for (int i = 0; i < 11; i++) {
					String name = "None";
					String desc = "No " + (invCursor == 3 ? "Item" : "Equip");
					int qty = 0;
					if (i + scrollIndex < inv.size()) {
						name = (invCursor == 3 ? ((Item) inv.get(i + scrollIndex)).getName()
								: ((Equip) inv.get(i + scrollIndex)).getName());
					}
					g.setColor(Color.gray);
					if (!name.equals("None")) {
						if (invCursor == 0) {
							name = ((Equip) inv.get(i + scrollIndex)).getName();
							desc = ((Equip) inv.get(i + scrollIndex)).description();
							qty = ((Equip) inv.get(i + scrollIndex)).getQty();
						} else if (invCursor == 1) {
							name = ((Equip) inv.get(i + scrollIndex)).getName();
							desc = ((Equip) inv.get(i + scrollIndex)).description();
							qty = ((Equip) inv.get(i + scrollIndex)).getQty();
						} else if (invCursor == 2) {
							name = ((Equip) inv.get(i + scrollIndex)).getName();
							desc = ((Equip) inv.get(i + scrollIndex)).description();
							qty = ((Equip) inv.get(i + scrollIndex)).getQty();
						} else if (invCursor == 3) {
							name = ((Item) inv.get(i + scrollIndex)).getName();
							desc = ((Item) inv.get(i + scrollIndex)).getDesc();
							qty = ((Item) inv.get(i + scrollIndex)).getQty();
						}
						g.setColor(Color.white);
					}
					g.drawString(name, leftX, yInc);
					g.drawString(qty + "", rightX
							- g.getFontMetrics().stringWidth(qty + "") + 6,
							yInc);
					g.setColor(Color.white);
					if (scrollCursor == i) {
						g.drawRect(leftX - 1, yInc + 5
								- g.getFontMetrics().getHeight(), g
								.getFontMetrics().stringWidth(name) + 2, g
								.getFontMetrics().getHeight());
						// Draw desc
						int prevFont = g.getFont().getSize();
						g.setFont(comicbook.deriveFont(16 * 1f));
						int botY = drawY + invWindow.getHeight() - 12
								- (g.getFontMetrics().getHeight() * 2);
						while (desc.length() > 0) {
							String temp = desc;
							desc = "";
							while (temp.length() > 0
									&& g.getFontMetrics().stringWidth(temp) > invWindow
									.getWidth() - 12) {
								int index = temp.lastIndexOf(" ");
								desc = temp.substring(index, temp.length())
										+ desc;
								temp = temp.substring(0, index);
							}
							g.drawString(temp, leftX, botY);
							botY += g.getFontMetrics().getHeight();
						}
						g.setFont(comicbook.deriveFont(prevFont * 1f));
					}
					yInc += 3 + g.getFontMetrics().getHeight();
				}
			} else if (curState.equals(State.Shop)) {
				int drawX = (windowWidth / 2) - (invWindow.getWidth() / 2);
				int drawY = (windowHeight / 2) - (invWindow.getHeight() / 2);
				g.drawImage(invWindow, drawX, drawY, null);
				for (int i = 0; i < invWindow.getWidth(); i++) {
					for (int j = 0; j < invWindow.getHeight(); j++) {
						Color temp = new Color(buffer.getRGB(drawX + i, drawY
								+ j));
						Color cur = new Color(invWindow.getRGB(i, j));
						if (cur.getRGB() == -16777216 && i >= 5
								&& i <= invWindow.getWidth() - 5 && j >= 5
								&& j <= invWindow.getHeight() - 5) {
							buffer.setRGB(
									drawX + i,
									drawY + j,
									new Color(temp.getRed() / 2, temp
											.getGreen() / 2, temp.getBlue() / 2)
									.getRGB());
						}
					}
				}
				g.setFont(comicbook);
				if (shopIndex == -1) {
					int buyLen = g.getFontMetrics().stringWidth("Buy");
					int centerX = drawX + (invWindow.getWidth() / 2);
					g.drawString("Buy", centerX - buyLen - 15, drawY
							+ (invWindow.getHeight() / 2)
							- (g.getFontMetrics().getHeight() / 2));
					g.drawString("Sell", centerX + 15,
							drawY + (invWindow.getHeight() / 2)
							- (g.getFontMetrics().getHeight() / 2));
					int drawFactor = drawY + (invWindow.getHeight() / 2)
							- ((g.getFontMetrics().getHeight() * 4) / 5);
					g.setColor(Color.white);
					int xPos = (invCursor == 0 ? centerX - 10 - buyLen
							: centerX + 20);
					g.fillPolygon(
							new int[] { xPos - 20, xPos - 10, xPos - 20 },
							new int[] { drawFactor - 10, drawFactor,
									drawFactor + 10 }, 3);
					g.setColor(Color.black);
					g.drawPolygon(
							new int[] { xPos - 20, xPos - 10, xPos - 20 },
							new int[] { drawFactor - 10, drawFactor,
									drawFactor + 10 }, 3);
					g.setColor(Color.white);
				} else {
					g.setColor(Color.black);
					g.drawLine(drawX + 5, drawY + 5
							+ g.getFontMetrics().getHeight() + 6, drawX
							+ invWindow.getWidth() - 5, drawY + 5
							+ g.getFontMetrics().getHeight() + 6);
					g.setColor(Color.white);
					String[] top = (shopIndex == 0 ? new String[] { "Equips",
							"Items", "Abilities" } : new String[] { "Equips",
							"Armors", "Weapons", "Items" });
					int stringWidths = 0;
					for (int i = 0; i < top.length; i++) {
						stringWidths += g.getFontMetrics().stringWidth(top[i]);
					}
					int spacing = (invWindow.getWidth() - 12 - stringWidths)
							/ top.length;
					stringWidths = 0;
					int yPos = 0;
					for (int i = 0; i < top.length; i++) {
						int xPos = drawX + 1 + (i * spacing) + stringWidths + 6;
						yPos = drawY + g.getFontMetrics().getHeight() + 5 + 3;
						g.drawString(top[i], xPos, yPos);
						if (i == invCursor) {
							g.drawRect(xPos - 1, yPos
									- g.getFontMetrics().getHeight() - 1, g
									.getFontMetrics().stringWidth(top[i]) + 2,
									g.getFontMetrics().getHeight() + 2);
						}
						xPos += g.getFontMetrics().stringWidth(top[i]);
						if (i != top.length - 1) {
							g.setColor(Color.black);
							g.drawLine(xPos + (spacing / 2), drawY + 5, xPos
									+ (spacing / 2), yPos + 3);
							g.setColor(Color.white);
						}
						stringWidths += g.getFontMetrics().stringWidth(top[i]);
					}
					ArrayList<Action> abilities = new ArrayList<Action>();
					for (int i = 0; i < maps[curMap].getAbilities().length; i++) {
						if (!playerData.getActions().contains(
								maps[curMap].getAbilities()[i])) {
							abilities.add(Utilities.findSomething(
									maps[curMap].getAbilities()[i], actions));
						}
					}
					String[] inv = null;
					if (invCursor == 0) {
						if (shopIndex == 0)
							inv = maps[curMap].equipsForSale();
						else
							inv = Utilities
							.toStringArray(playerData.getInv().helms);
					}
					if (invCursor == 1) {
						if (shopIndex == 0)
							inv = maps[curMap].itemsForSale();
						else
							inv = Utilities
							.toStringArray(playerData.getInv().armors);
					}
					if (invCursor == 2) {
						if (shopIndex == 0)
							inv = Utilities.toStringArray(abilities);
						else
							inv = Utilities
							.toStringArray(playerData.getInv().weapons);
					} else if (invCursor == 3 && shopIndex == 1) {
						inv = Utilities
								.toStringArray(playerData.getInv().items);
					}
					int leftX = drawX + 6;
					int rightX = drawX + invWindow.getWidth() - 12;
					g.setFont(comicbook.deriveFont(15f));
					int yInc = yPos + 2 + g.getFontMetrics().getHeight();
					g.drawString("Gold: " + playerData.getGold(), leftX, yInc);
					yInc += g.getFontMetrics().getHeight() + 2;
					g.drawString("Name", leftX, yInc);
					g.drawString("Price", rightX
							- g.getFontMetrics().stringWidth("Price"), yInc);
					if (!(shopIndex == 0 && invCursor == 2))
						g.drawString("Owned", drawX
								+ ((invWindow.getWidth() * 6) / 8)
								- g.getFontMetrics().stringWidth("Owned"), yInc);
					yInc += g.getFontMetrics().getHeight() + 2;
					for (int i = 0; i < 11; i++) {
						String name = "None";
						String desc = "No ";
						if ((invCursor < 3 && shopIndex == 1) || invCursor == 0) {
							desc += "Equip";
						} else if ((invCursor == 3 && shopIndex == 1)
								|| (invCursor == 1))
							desc += "Item";
						else
							desc += "Action";
						int price = 0;
						int qty = 0;
						if (inv != null && i + scrollIndex < inv.length) {
							name = inv[i + scrollIndex];
						}
						g.setColor(Color.gray);
						if (!name.equals("None")) {
							if (invCursor == 0) {
								Equip temp = Utilities.findSomething(name,
										equips);
								desc = temp.description();
								price = (shopIndex == 0) ? temp.getCost()
										: temp.getSellPrice();
								int indexHelm = Utilities.findIndex(name, playerData.getInv().helms);
								int indexArmor = Utilities.findIndex(name, playerData.getInv().armors);
								int indexWeapon = Utilities.findIndex(name, playerData.getInv().weapons);
								if (shopIndex == 1
										&& !(indexHelm == -1))
									qty = playerData.getInv().helms.get(indexHelm).getQty();
								else {
									Equip.Type t = temp.getType();
									if (t.equals(Equip.Type.Armor)
											&& !(indexArmor == -1))
										qty = playerData.getInv().armors.get(indexArmor).getQty();
									else if (t.equals(Equip.Type.Helm)
											&& !(indexHelm == -1))
										qty = playerData.getInv().helms.get(indexHelm).getQty();
									else if (t.equals(Equip.Type.Weapon)
											&& !(indexWeapon == -1))
										qty = playerData.getInv().weapons.get(indexWeapon).getQty();
								}
							} else if (invCursor == 1) {
								if (shopIndex == 0) {
									Item temp = Utilities.findSomething(name,
											items);
									desc = temp.getDesc();
									price = temp.getCost();
									int index = Utilities.findIndex(name, playerData.getInv().items);
									if (!(index == -1))
										qty = playerData.getInv().items.get(index).getQty();
								} else {
									Equip temp = Utilities.findSomething(name,
											equips);
									desc = temp.description();
									price = temp.getSellPrice();
									int index = Utilities.findIndex(name, playerData.getInv().armors);
									if (!(index == -1))
										qty = playerData.getInv().armors.get(index).getQty();
								}
								// find prev qty
							} else if (invCursor == 2) {
								if (shopIndex == 0) {
									desc = Utilities.findSomething(name,
											actions).getDescription();
									price = maps[curMap].abilitySale(name);
								} else {
									Equip temp = Utilities.findSomething(name,
											equips);
									desc = temp.description();
									price = temp.getSellPrice();
									int index = Utilities.findIndex(name, playerData.getInv().weapons);
									if (!(index == -1))
										qty = playerData.getInv().weapons.get(index).getQty();
								}
							} else if (invCursor == 3 && shopIndex == 1) {
								Item temp = Utilities
										.findSomething(name, items);
								desc = temp.getDesc();
								price = temp.getSellPrice();
								int index = Utilities.findIndex(name, playerData.getInv().items);
								if (!(index == -1))
									qty = playerData.getInv().items.get(index).getQty();
							}
							g.setColor(Color.white);
						}
						g.drawString(name, leftX, yInc);
						g.drawString(price + "", rightX
								- g.getFontMetrics().stringWidth(price + ""),
								yInc);
						if (!(shopIndex == 0 && invCursor == 2))
							g.drawString(
									qty + "",
									drawX
									+ ((invWindow.getWidth() * 6) / 8)
									- g.getFontMetrics().stringWidth(
											qty + ""), yInc);
						g.setColor(Color.white);
						if (scrollCursor == i) {
							g.drawRect(leftX - 1, yInc + 5
									- g.getFontMetrics().getHeight(), g
									.getFontMetrics().stringWidth(name) + 2, g
									.getFontMetrics().getHeight());
							// Draw desc
							int prevFont = g.getFont().getSize();
							g.setFont(comicbook.deriveFont(16 * 1f));
							int botY = drawY + invWindow.getHeight() - 12
									- (g.getFontMetrics().getHeight() * 2);
							while (desc.length() > 0) {
								String temp = desc;
								desc = "";
								while (temp.length() > 0
										&& g.getFontMetrics().stringWidth(temp) > invWindow
										.getWidth() - 12) {
									int index = temp.lastIndexOf(" ");
									desc = temp.substring(index, temp.length())
											+ desc;
									temp = temp.substring(0, index);
								}
								g.drawString(temp, leftX, botY);
								botY += g.getFontMetrics().getHeight();
							}
							g.setFont(comicbook.deriveFont(prevFont * 1f));
						}
						yInc += 3 + g.getFontMetrics().getHeight();
					}
				}
			}
		} else if (curState.name().contains("Battle")
				|| (curState.equals(State.Transition) && curMap == 0)
				|| (curState.equals(State.PostTransition) && curMap == 0)) {
			for (int i = 0; i < windowWidth; i++) {
				for (int j = 0; j < windowHeight; j++) {
					buffer.setRGB(
							i,
							j,
							maps[prevMap].image().getRGB(24 + (i % 24),
									24 + (j % 24)));
				}
			}
			g.drawImage(maps[curMap].image(), 0, 0, null);
			if((state.equals(State.BattlePlayerAnimation) || state.equals(State.BattleEnemyAnimation)) &&
					(-1 != Utilities.findIndex(battle.currentAction(), animates) ||
					!battle.playerAction().getCommand().contains("damage"))){
				Polygon poly = (Polygon) ((state.equals(State.BattleEnemyAnimation)) ? 
						battleWindows[2] : battleWindows[1]);
				int index = -1;
				boolean cont = true;
				if(state.equals(State.BattlePlayerAnimation) &&
						!battle.playerAction().getCommand().contains("damage")){
					index = Utilities.findIndex("Heal", animates);
					poly = battleWindows[2];
					cont = false;
				}
				Rectangle bounds = poly.getBounds();
				BufferedImage bi = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB);
				if(index == -1) 
					index = Utilities.findIndex(battle.currentAction(), animates);
				bi.getGraphics().drawImage(animates.get(index).currentAniState(animCounter), 0, 0, bi.getWidth(), bi.getHeight()
						, 0, 0, animates.get(index).width, animates.get(index).width, null);
				if(poly.equals(battleWindows[2]))
					bi = Utilities.flip(bi);
				for(int i = 0; i < bounds.width; i++){
					for(int j = 0; j < bounds.height; j++){
						int x = (int) (i + bounds.getMinX());
						int y = (int) (j + bounds.getMinY());
						if(poly.contains(x, y))
							buffer.setRGB(x, y, bi.getRGB(i, j));
					}
				}
				if(cont){
					BufferedImage bi2 = animates.get(index).background();
					if(state.equals(State.BattleEnemyAnimation)) bi2 = Utilities.flip(bi2);
					if(poly.equals(battleWindows[1]))
						poly = battleWindows[2];
					else
						poly = battleWindows[1];
					bounds = poly.getBounds();
					BufferedImage bi3 = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB);
					bi3.getGraphics().drawImage(bi2, 0, 0, bi3.getWidth(), bi3.getHeight()
							, 0, 0, bi2.getWidth(), bi2.getHeight(), null);
					for(int i = 0; i < bounds.width; i++){
						for(int j = 0; j < bounds.height; j++){
							int x = (int) (i + bounds.getMinX());
							int y = (int) (j + bounds.getMinY());
							if(poly.contains(x, y))
								buffer.setRGB(x, y, bi3.getRGB(i, j));
						}
					}
				}
			}
			if((state.equals(State.BattlePlayerAttack) || state.equals(State.BattleEnemyAttack))){
				Polygon poly = null;
				int index = -1;
				index = Utilities.findIndex(battle.currentAction(), animates);
				if(index != -1){
					BufferedImage bi2 = animates.get(index).background();
					if(state.equals(State.BattleEnemyAnimation)) bi2 = Utilities.flip(bi2);
					poly = (Polygon) ((state.equals(State.BattleEnemyAttack)) ? 
							battleWindows[1] : battleWindows[2]);
					Rectangle bounds = poly.getBounds();
					BufferedImage bi3 = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB);
					bi3.getGraphics().drawImage(bi2, 0, 0, bi3.getWidth(), bi3.getHeight()
							, 0, 0, bi2.getWidth(), bi2.getHeight(), null);
					if(poly.equals(battleWindows[1]))
						bi3 = Utilities.flip(bi3);
					for(int i = 0; i < bounds.width; i++){
						for(int j = 0; j < bounds.height; j++){
							int x = (int) (i + bounds.getMinX());
							int y = (int) (j + bounds.getMinY());
							if(poly.contains(x, y))
								buffer.setRGB(x, y, bi3.getRGB(i, j));
						}
					}
				}
			}
			if (state.equals(State.BattlePlayerAttack)) {
				int index = 1;
				if (battle.playerAction().getCommand().contains("damage")
						&& !battle.playerAction().getCommand().contains("mdamage")) {
					index++;
					if (off == 1)
						index++;
				} else if(-1 == Utilities.findIndex(battle.playerAction().getName(), actions)){
					if (off == 1)
						index += 4;
					else
						index += 3;
				} else{
					if(off == 1)
						index--;
				}
				playerBattle.setState(index);
			}
			if(state.equals(State.BattleVictory))
				playerBattle.setState(2 + (off < 0 ? 0 : off));
			if (state.equals(State.BattleBackward))
				g.drawImage(Utilities.flip(playerBattle.currentImage()),
						playerBattle.x, playerBattle.y, null);
			else if (state.equals(State.BattlePlayerDamage) && off == -1) {
				g.drawImage(Utilities.invert(playerBattle.currentImage()),
						playerBattle.x - 1, playerBattle.y - 1, null);
			} else
				g.drawImage(playerBattle.currentImage(), playerBattle.x,
						playerBattle.y, null);
			if (state.equals(State.BattlePlayerNumber) || (state.equals(State.BattleEnemyNumber)
					&& !battle.playerAction().getCommand().contains("damage"))) {
				float font = g.getFont().getSize();
				int raise = Math.abs(animCounter - 6);
				if(raise > 3)
					raise = 3;
				g.setFont(comicbook.deriveFont(10f));
				int xDisp = playerBattle.x + playerBattle.width;
				int yDisp = playerBattle.y + g.getFontMetrics().getHeight();
				if(battle.wasLastCrit())
					g.drawString("Crit!", playerBattle.x, playerBattle.y + playerBattle.height + g.getFontMetrics().getHeight());
				g.setFont(comicbook.deriveFont(10f + raise));
				if (animCounter == 6 || animCounter <= 4)
					yDisp -= 10;
				else if (animCounter == 5)
					yDisp -= 20;
				Action temp = null;
				if(state.equals(State.BattleEnemyNumber))
					temp = battle.playerAction();
				else
					temp = Utilities.findSomething(battle.currentAction(),
							actions);
				g.drawString(
						battle.processCommand(temp.getCommand(),
								battle.currentTurn(), playerData)
								+ "", xDisp, yDisp);
				// Logic for quantitative image
				g.setFont(comicbook.deriveFont(font));
			}
			// Draw title
			float font = 30f;
			Rectangle temp = battleWindows[0].getBounds();
			String title = "Issue: Maleable Man vs " + battle.descEnemies();
			while (g.getFontMetrics(comicbook.deriveFont(font)).stringWidth(
					title) > temp.getWidth())
				font--;
			g.setFont(comicbook.deriveFont(font));
			int centerX = (int) ((temp.getWidth() / 2) + temp.getMinX() - (g
					.getFontMetrics().stringWidth(title) / 2));
			int centerY = (int) (temp.getMinY() + (temp.getHeight() / 2) + (g
					.getFontMetrics().getHeight() / 2));
			g.drawString(title, centerX, centerY);
			g.setFont(comicbook);
			// Draw enemies and stat bars
			temp = battleWindows[1].getBounds();
			int numEnemies = battle.getBaddies().size();
			String enemy = battle.getBaddies().get(0).getName();
			BufferedImage bi = enemyImages.get(enemy);
			int xSpacing = ((int) (temp.getWidth() / 2) - (bi.getWidth() * numEnemies))
					/ (numEnemies + 1);
			int yPos = (int) (temp.getWidth() / 2) - (bi.getHeight() / 2);
			Rectangle temp2 = battleWindows[3].getBounds();
			int xBar = (int) (temp2.getMinX() + 5);
			int yBar = (int) (temp2.getMinY() + 5);
			g.setFont(comicbook.deriveFont(14f));
			for (int i = 0; i < 4; i++) {
				if (i < 3 && i < numEnemies) {
					int enmX = (int) temp.getMinX() + ((i + 1) * xSpacing)
							+ (i * bi.getWidth());
					int enmY = yPos + (int) temp.getMinY();
					if (battle.getBaddies().get(i).getCurHp() == 0) {
						if (state.equals(State.BattleEnemyDeath)
								&& isMember(battle.getTarget(), i)){
							int limJ = (bi.getWidth() - ((bi.getWidth() * animCounter)/ 4));
							int limK = (bi.getHeight() - ((bi.getHeight() * animCounter)/ 4));
							for(int j = 0; j < bi.getWidth(); j++){
								for(int k = 0; k < bi.getHeight(); k++){
									buffer.setRGB(enmX + j, enmY + k, (j < limJ && k < limK ? bi.getRGB(j, k) : 0));
								}
							}
						}
					} else {
						if (((state.equals(State.BattleEnemyDamage) && isMember(
								battle.getTarget(), i)) || (state
										.equals(State.BattleEnemyAttack) && battle
										.currentTurn() == battle.getBaddies().get(i)))
										&& off == -1) {
							g.drawImage(Utilities.invert(bi), enmX - 1,
									enmY - 1, null);
						} else {
							g.drawImage(bi, enmX, enmY, null);
						}
					}
					if (state.equals(State.BattleEnemyNumber)
							&& isMember(battle.getTarget(), i)
							&& battle.getBaddies().get(i).getCurHp() != 0) {
						float fnt = g.getFont().getSize();
						g.setFont(comicbook.deriveFont(10f));
						int xDisp = enmX + bi.getWidth();
						int yDisp = enmY + g.getFontMetrics().getHeight();
						int raise = Math.abs(animCounter - 6);
						if(raise > 3)
							raise = 3;
						g.setFont(comicbook.deriveFont(10f));
						if(battle.wasLastCrit())
							g.drawString("Crit!", enmX, enmY + bi.getHeight() + g.getFontMetrics().getHeight());
						g.setFont(comicbook.deriveFont(10f + raise));
						if (animCounter == 6 || animCounter <= 4)
							yDisp -= 10;
						else if (animCounter == 5)
							yDisp -= 20;
						Action a = Utilities.findSomething(
								battle.currentAction(), actions);
						g.drawString(
								battle.processCommand(a.getCommand(),
										playerData, battle.getBaddies().get(i))
										+ "", xDisp, yDisp);
						// Logic for quantitative image
						g.setFont(comicbook.deriveFont(fnt));
					}
					if (state.equals(State.BattleCursor)
							&& !battle.playerAction().getCommand()
							.contains("damage"))
						;
					else if (state.equals(State.BattleCursor)
							&& (invCursor == i || battle.playerAction()
							.getDescription().contains("all foes"))
							&& battle.getBaddies().get(i).getCurHp() != 0) {
						int cenX = enmX + bi.getWidth() / 2;
						int cenY = enmY + bi.getHeight() / 2;
						g.setColor(Color.white);
						g.fillPolygon(new int[] { cenX - 10, cenX, cenX + 10 },
								new int[] { cenY - 10, cenY, cenY - 10 }, 3);
						g.setColor(Color.black);
						g.drawPolygon(new int[] { cenX - 10, cenX, cenX + 10 },
								new int[] { cenY - 10, cenY, cenY - 10 }, 3);
						g.setColor(Color.white);
					}
					if (battle.getBaddies().get(i).getCurHp() > 0) {
						g.drawImage(statBar, xBar, yBar, null);
						g.setColor(Color.red);
						g.fillRect(xBar + 5, yBar + 5, (battle.getBaddies()
								.get(i).getCurHp() * 40)
								/ battle.getBaddies().get(i).getHp(), 5);
						g.setColor(Color.white);
						String hp = battle.getBaddies().get(i).getCurHp() + "/"
								+ battle.getBaddies().get(i).getHp();
						g.drawString(hp, xBar, yBar + statBar.getHeight()
								+ g.getFontMetrics().getHeight());
					}
				} else if (i == 3) {
					int yTemp = yBar;
					g.drawImage(statBar, (int) xBar, yTemp, null);
					g.setColor(Color.red);
					g.fillRect(xBar + 5, yTemp + 5,
							(playerData.getCurHp() * 40) / playerData.getHp(),
							5);
					g.setColor(Color.white);
					String hp = playerData.getCurHp() + "/"
							+ playerData.getHp();
					g.drawString(hp, xBar, yTemp + statBar.getHeight()
							+ g.getFontMetrics().getHeight());
					yTemp += statBar.getHeight()
							+ g.getFontMetrics().getHeight() + 5;
					g.drawImage(statBar, (int) xBar, yTemp, null);
					g.setColor(Color.blue);
					g.fillRect(xBar + 5, yTemp + 5,
							(playerData.getCurMp() * 40) / playerData.getMp(),
							5);
					g.setColor(Color.white);
					String mp = playerData.getCurMp() + "/"
							+ playerData.getMp();
					g.drawString(mp, xBar, yTemp + statBar.getHeight()
							+ g.getFontMetrics().getHeight());
					if (state.equals(State.BattleCursor)
							&& !battle.playerAction().getCommand()
							.contains("damage")) {
						int cenX = playerBattle.x + playerBattle.width / 2;
						int cenY = playerBattle.y + playerBattle.height / 2;
						g.setColor(Color.white);
						g.fillPolygon(new int[] { cenX - 10, cenX, cenX + 10 },
								new int[] { cenY - 10, cenY, cenY - 10 }, 3);
						g.setColor(Color.black);
						g.drawPolygon(new int[] { cenX - 10, cenX, cenX + 10 },
								new int[] { cenY - 10, cenY, cenY - 10 }, 3);
						g.setColor(Color.white);
					}
				}
				xBar += statBar.getWidth() + 40;
			}
			xBar -= 10;
			g.setColor(Color.black);
			g.drawLine(xBar, yBar - 5, xBar, (int) (temp2.getMaxY()));
			g.setColor(Color.white);
			if (curState.equals(State.BattleMenu)
					|| curState.equals(State.BattleCursor)) {
				xBar += 3;
				yBar -= 2;
				for (int i = 0; i < 5; i++) {
					String name = "None";
					String desc = "No Action Available";
					if (i + scrollIndex == 0) {
						name = "Attack";
						Action act = Utilities.findSomething(name, actions);
						desc = act.getDescription();
					} else if (i + scrollIndex - 1 < playerData.getActions()
							.size()) {
						Action act = Utilities.findSomething(
								playerData.getActions().get(
										scrollIndex + i - 1),
										actions);
						name = act.getName();
						desc = act.getDescription();
					} else if (i + scrollIndex - 1 == playerData.getActions()
							.size()) {
						name = "Run";
						Action act = Utilities.findSomething(name, actions);
						desc = act.getDescription();
					}
					else if(i + scrollIndex - 2 == playerData.getActions().size()){
						name = "Item";
						desc = "Choose an item to use";
					}
					g.drawString(name, xBar, yBar
							+ g.getFontMetrics().getHeight());
					if (scrollCursor == i) {
						float oldFont = g.getFont().getSize();
						g.setFont(comicbook.deriveFont(12f));
						g.drawString(desc, (int) temp2.getMinX() + 7,
								(int) temp2.getMaxY() + 7
								+ g.getFontMetrics().getHeight());
						g.setFont(comicbook.deriveFont(oldFont));
						g.drawRect(xBar - 1, yBar - 1, g.getFontMetrics()
								.stringWidth(name) + 2, g.getFontMetrics()
								.getHeight() + 2);
					}
					yBar += g.getFontMetrics().getHeight() + 3;
				}
			}
			if (curState.equals(State.BattleMessage) || curState.equals(State.BattleVictory)) {
				float fnt = g.getFont().getSize();
				g.setFont(comicbook.deriveFont(18f));
				int back = trans;
				trans = 1;
				for (int i = 0; i < windowWidth; i++) {
					for (int j = 0; j < windowHeight; j++) {
						buffer.setRGB(i, j, fade(buffer.getRGB(i, j)));
					}
				}
				trans = back;
				g.drawString(message, (windowWidth / 2)
						- (g.getFontMetrics().stringWidth(message) / 2),
						(windowHeight / 2)
						+ (g.getFontMetrics().getHeight() / 2));
				g.setFont(comicbook.deriveFont(fnt));
			}
			if(state.equals(State.BattleInventory)){
				int drawX = (windowWidth / 2) - (invWindow.getWidth() / 2);
				int drawY = (windowHeight / 2) - (invWindow.getHeight() / 2);
				g.drawImage(invWindow, drawX, drawY, null);
				for (int i = 0; i < invWindow.getWidth(); i++) {
					for (int j = 0; j < invWindow.getHeight(); j++) {
						Color col = new Color(buffer.getRGB(drawX + i, drawY
								+ j));
						Color cur = new Color(invWindow.getRGB(i, j));
						if (cur.getRGB() == -16777216 && i >= 5
								&& i <= invWindow.getWidth() - 5 && j >= 5
								&& j <= invWindow.getHeight() - 5) {
							buffer.setRGB(
									drawX + i,
									drawY + j,
									new Color(col.getRed() / 2, col
											.getGreen() / 2, col.getBlue() / 2)
									.getRGB());
						}
					}
				}
				g.setFont(comicbook);
				g.setColor(Color.black);
				g.drawLine(drawX + 5, drawY + 5
						+ g.getFontMetrics().getHeight() + 6,
						drawX + invWindow.getWidth() - 5, drawY + 5
						+ g.getFontMetrics().getHeight() + 6);
				g.setColor(Color.white);
				int xPos = drawX + (invWindow.getWidth() / 2) - g.getFontMetrics().stringWidth("Items");
				int yTop = drawY + g.getFontMetrics().getHeight() + 5 + 3;
				g.drawString("Items", xPos, yTop);
				int leftX = drawX + 6;
				int rightX = drawX + ((invWindow.getWidth() * 7) / 8);
				int yInc = yTop + 2 + g.getFontMetrics().getHeight();
				g.drawString("Name", leftX, yInc);
				g.drawString("Qty",
						rightX - g.getFontMetrics().stringWidth("Qty"), yInc);
				yInc += g.getFontMetrics().getHeight() + 2;
				g.setFont(comicbook.deriveFont(15f));
				for (int i = 0; i < 11; i++) {
					String name = "None";
					String desc = "No Item";
					if (i + scrollIndex < playerData.getInv().items.size()) {
						name = playerData.getInv().items.get(i + scrollIndex).getName();
					}
					int qty = 0;
					g.setColor(Color.gray);
					if (!name.equals("None")) {
						name = ((Item) playerData.getInv().items.get(i + scrollIndex)).getName();
						desc = ((Item) playerData.getInv().items.get(i + scrollIndex)).getDesc();
						qty = ((Item) playerData.getInv().items.get(i + scrollIndex)).getQty();
						g.setColor(Color.white);
					}
					g.drawString(name, leftX, yInc);
					g.drawString(qty + "", rightX
							- g.getFontMetrics().stringWidth(qty + "") + 6,
							yInc);
					g.setColor(Color.white);
					if (battleCursor == i) {
						g.drawRect(leftX - 1, yInc + 5
								- g.getFontMetrics().getHeight(), g
								.getFontMetrics().stringWidth(name) + 2, g
								.getFontMetrics().getHeight());
						// Draw desc
						int prevFont = g.getFont().getSize();
						g.setFont(comicbook.deriveFont(16 * 1f));
						int botY = drawY + invWindow.getHeight() - 12
								- (g.getFontMetrics().getHeight() * 2);
						while (desc.length() > 0) {
							String tempDesc = desc;
							desc = "";
							while (tempDesc.length() > 0
									&& g.getFontMetrics().stringWidth(tempDesc) > invWindow
									.getWidth() - 12) {
								int index = tempDesc.lastIndexOf(" ");
								desc = tempDesc.substring(index, tempDesc.length())
										+ desc;
								tempDesc = tempDesc.substring(0, index);
							}
							g.drawString(tempDesc, leftX, botY);
							botY += g.getFontMetrics().getHeight();
						}
						g.setFont(comicbook.deriveFont(prevFont * 1f));
					}
					yInc += 3 + g.getFontMetrics().getHeight();
				}
			}
			if (curState.equals(State.Transition)
					|| curState.equals(State.PostTransition)
					|| curState.equals(State.BattlePlayerDeath)) {
				for (int i = 0; i < windowWidth; i++) {
					for (int j = 0; j < windowHeight; j++) {
						buffer.setRGB(i, j, fade(buffer.getRGB(i, j)));
					}
				}
			}
		} else if (curState.equals(State.Begin)) {
			g.setColor(new Color(153, 217, 234));
			g.fillRect(0, 0, windowWidth, windowHeight);
			int centerX = windowWidth / 2 - (menu.getWidth() / 2);
			int sixthY = windowHeight / 6;
			g.setColor(Color.white);
			g.drawImage(menu, centerX, sixthY, null);
			g.setFont(comicbook.deriveFont(28f));
			int middleX1 = (menu.getWidth() / 2) + centerX
					- (g.getFontMetrics().stringWidth("The") / 2);
			int middleX2 = (menu.getWidth() / 2) + centerX
					- (g.getFontMetrics().stringWidth("Mutable") / 2) - 7;
			int middleX3 = (menu.getWidth() / 2) + centerX
					- (g.getFontMetrics().stringWidth("Man") / 2);
			g.drawString("The", middleX1, sixthY + 5
					+ g.getFontMetrics().getHeight());
			g.drawString("Maleable", middleX2, sixthY + 5
					+ (g.getFontMetrics().getHeight() * 2));
			g.drawString("Man", middleX3, sixthY + 5
					+ (g.getFontMetrics().getHeight() * 3));
			int prev = playerBattle.getState();
			playerBattle.setState(3);
			int middleX = (windowWidth / 2)
					- (playerBattle.currentImage().getWidth() / 2);
			int thirdY = sixthY + menu.getHeight() + playerBattle.height;
			g.drawImage(playerBattle.currentImage(), middleX, thirdY, null);
			playerBattle.setState(prev);
			g.setFont(comicbook);
			for (int i = 0; i < beginOptions.length; i++) {
				int length = (int) g.getFontMetrics().stringWidth(
						beginOptions[i]);
				int dispX = (windowWidth / 2) - (length / 2);
				int height = g.getFontMetrics().getHeight();
				int dispY = thirdY
						+ (playerBattle.currentImage().getHeight() * 2) + 5
						+ (i * height) + ((height * 3) / 4);
				g.drawString(beginOptions[i], dispX, dispY);
				if (beginCursor == i) {
					int drawX = dispX - 30;
					int drawFactor = (int) g.getFontMetrics()
							.getStringBounds(beginOptions[i], g).getBounds()
							.getCenterY();
					g.setColor(Color.white);
					g.fillPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] { dispY + drawFactor - 10,
							dispY + drawFactor, dispY + drawFactor + 10 }, 3);
					g.setColor(Color.black);
					g.drawPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] { dispY + drawFactor - 10,
							dispY + drawFactor, dispY + drawFactor + 10 }, 3);
					g.setColor(Color.white);
				}
			}
		} else if (curState.equals(State.Credits)) {
			g.setColor(new Color(153, 217, 234));
			g.fillRect(0, 0, windowWidth, windowHeight);
			g.setColor(Color.white);
			g.setFont(comicbook);
			int count = 0;
			for (int i = 0; i < creditLines.length; i++) {
				int length = (int) g.getFontMetrics().stringWidth(
						creditLines[i]);
				int dispX = (windowWidth / 2) - (length / 2);
				int height = g.getFontMetrics().getHeight();
				int dispY = 100 + (i * height) + ((height * 3) / 4);
				g.drawString(creditLines[i], dispX, dispY);
				if (creditLines[i].contains(":")) {
					int state = (count == 0 ? 4 : (count == 1 ? 0 : 2));
					int prev = playerBattle.getState();
					playerBattle.setState(state);
					g.drawImage(playerBattle.currentImage(), 40, dispY, null);
					int xPos = windowWidth - 40;
					g.drawImage(playerBattle.currentImage(), xPos, dispY, xPos
							- playerBattle.width, dispY + playerBattle.height,
							0, 0, playerBattle.width, playerBattle.height, null);
					playerBattle.setState(prev);
					count++;
				}
			}
			g.setFont(comicbook.deriveFont(12f));
			int length = (int) g.getFontMetrics().stringWidth(
					"Press enter to coninue");
			g.drawString("Press enter to continue", (windowWidth / 2)
					- (length / 2), windowHeight - 100);
			g.setFont(comicbook);
		} else if (curState.equals(State.Save) || state.equals(State.Load)) {
			g.setColor(new Color(153, 217, 234));
			g.fillRect(0, 0, windowWidth, windowHeight);
			g.setColor(Color.white);
			g.drawImage(saveWindow, 0, 0, null);
			g.setFont(comicbook);
			int count = 0;
			for (File f : new File[] { save1, save2 }) {
				String saveTitle = "";
				int middleX = 120 + (count * 240);
				int topCenterY = 51;
				int bottomY = topCenterY * 2 + 6;
				if (f == null || writing) {
					saveTitle = "Empty";
				} else {
					saveTitle = "Slot " + (count + 1);
					// Fill in info for slot.
					Player p = null;
					try {
						p = peekGame(f);
					} catch (IOException e) {
						e.printStackTrace();
						System.exit(0);
					}
					g.setFont(comicbook.deriveFont(14f));
					bottomY += g.getFontMetrics().getHeight() * 2;
					String level = "Level: " + p.getLevel();
					int expToLevel = (int) (Math.pow(p.getLevel(), 2)
							* (25 + (p.getLevel() > 9 ? Math
									.ceil(p.getLevel() / 1.3) : p.getLevel())) + 25);
					String exp = "Exp: " + p.getExp() + "/" + expToLevel;
					String gold = "Gold: " + p.getGold();
					String hp = "Hp: " + p.getCurHp() + "/" + p.getHp();
					String mp = "Mp: " + p.getCurMp() + "/" + p.getMp();
					String mdef = "Mdef: " + p.getMdef();
					String def = "Def: " + p.getDef();
					String str = "Str: " + p.getStr();
					String Int = "Int: " + p.getInt(); 
					String speed = "Spd: " + p.getSpeed();
					String helm = (p.getHelm() == null ? "Helm: None"
							: "Helm: " + p.getHelm().getName());
					String armor = (p.getArmor() == null ? "Armor: None"
							: "Armor: " + p.getArmor().getName());
					String weapon = (p.getWeapon() == null ? "Weapon: None"
							: "Weapon: " + p.getWeapon().getName());
					for (String string : new String[] { level, exp, gold, hp,
							mp, mdef, def, str, Int, speed, helm, armor, weapon }) {
						int xPos = middleX
								- (g.getFontMetrics().stringWidth(string) / 2);
						g.drawString(string, xPos, bottomY);
						bottomY += g.getFontMetrics().getHeight();
					}
				}
				g.setFont(comicbook);
				int width = g.getFontMetrics().stringWidth(saveTitle) / 2;
				int height = g.getFontMetrics().getHeight() / 2;
				g.drawString(saveTitle, middleX - width, topCenterY + height);
				// Draw titles
				if (count == saveCursor && !substate.equals(State.Confirm)) {
					int drawX = middleX - 90;
					int drawFactor = (int) g.getFontMetrics()
							.getStringBounds(saveTitle, g).getBounds()
							.getCenterY();
					g.setColor(Color.white);
					g.fillPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] {
							topCenterY - drawFactor - 10,
							topCenterY - drawFactor,
							topCenterY - drawFactor + 10 }, 3);
					g.setColor(Color.black);
					g.drawPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] {
							topCenterY - drawFactor - 10,
							topCenterY - drawFactor,
							topCenterY - drawFactor + 10 }, 3);
					g.setColor(Color.white);
				}
				count++;
			}
		} else if (curState.equals(State.Confirm)) {
			drawBuffer(substate);
			int drawX = (windowWidth / 2) - (menu.getWidth() / 2);
			int drawY = (windowHeight / 2) - (menu.getHeight() / 2);
			g.drawImage(menu, drawX, drawY, null);
			for (int i = 0; i < menu.getWidth(); i++) {
				for (int j = 0; j < menu.getHeight(); j++) {
					Color temp = new Color(buffer.getRGB(drawX + i, drawY + j));
					Color cur = new Color(menu.getRGB(i, j));
					if (cur.getRGB() == -16777216 && i >= 5
							&& i <= menu.getWidth() - 5 && j >= 5
							&& j <= menu.getHeight() - 5) {
						buffer.setRGB(
								drawX + i,
								drawY + j,
								new Color(temp.getRed() / 2,
										temp.getGreen() / 2, temp.getBlue() / 2)
								.getRGB());
					}
				}
			}
			g.setFont(comicbook);
			int i = -1;
			for (String str : new String[] { message, "No", "Yes" }) {
				int length = (int) g.getFontMetrics().stringWidth(str);
				int dispX = (windowWidth / 2) - (length / 2);
				int height = g.getFontMetrics().getHeight();
				int dispY = drawY + 5 + ((i + 1) * height) + ((height * 3) / 4);
				g.drawString(str, dispX, dispY);
				if (confirmCursor >= 0 && confirmCursor == i) {
					int drawFactor = (int) g.getFontMetrics()
							.getStringBounds(str, g).getBounds().getCenterY();
					g.setColor(Color.white);
					g.fillPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] { dispY + drawFactor - 10,
							dispY + drawFactor, dispY + drawFactor + 10 }, 3);
					g.setColor(Color.black);
					g.drawPolygon(new int[] { drawX + 10, drawX + 20,
							drawX + 10 }, new int[] { dispY + drawFactor - 10,
							dispY + drawFactor, dispY + drawFactor + 10 }, 3);
					g.setColor(Color.white);
				}
				i++;
			}
		} else if (curState.equals(State.Message)) {
			drawBuffer(substate);
			int drawX = (windowWidth / 2) - (menu.getWidth() / 2);
			int drawY = (windowHeight / 2) - (menu.getHeight() / 2);
			g.drawImage(menu, drawX, drawY, null);
			for (int i = 0; i < menu.getWidth(); i++) {
				for (int j = 0; j < menu.getHeight(); j++) {
					Color temp = new Color(buffer.getRGB(drawX + i, drawY + j));
					Color cur = new Color(menu.getRGB(i, j));
					if (cur.getRGB() == -16777216 && i >= 5
							&& i <= menu.getWidth() - 5 && j >= 5
							&& j <= menu.getHeight() - 5) {
						buffer.setRGB(
								drawX + i,
								drawY + j,
								new Color(temp.getRed() / 2,
										temp.getGreen() / 2, temp.getBlue() / 2)
								.getRGB());
					}
				}
			}
			int i = -1;
			Scanner sc = new Scanner(message);
			while (sc.hasNext()) {
				String str = sc.next();
				int length = (int) g.getFontMetrics().stringWidth(str);
				int dispX = (windowWidth / 2) - (length / 2);
				int height = g.getFontMetrics().getHeight();
				int dispY = drawY + 5 + ((i + 1) * height) + ((height * 3) / 4);
				g.drawString(str, dispX, dispY);
				i++;
			}
		} else if (state.equals(State.GameOver)) {
			g.setColor(Color.black);
			g.fillRect(0, 0, windowWidth, windowHeight);
			g.setColor(Color.white);
			g.setFont(comicbook.deriveFont(40f));
			g.drawString("Game Over", (windowWidth / 2)
					- (g.getFontMetrics().stringWidth("Game Over") / 2),
					(windowHeight / 2) + (g.getFontMetrics().getHeight() / 2));
		}
		else if(state.equals(State.GameWon)){
			g.setColor(Color.black);
			g.fillRect(0, 0, windowWidth, windowHeight);
			g.setColor(Color.white);
			g.setFont(comicbook.deriveFont(32f));
			g.drawString("Congrats! Enjoy this 30k gold bounty!", (windowWidth / 2)
					- (g.getFontMetrics().stringWidth("Game Over") / 2),
					(windowHeight / 2) + (g.getFontMetrics().getHeight() / 2));
		}
	}

	private boolean isMember(Player[] target, int index) {
		for (int j = 0; j < target.length; j++) {
			if (battle.getBaddies().get(index) == target[j])
				return true;
		}
		return false;
	}

	public void drawScreen() {
		Graphics2D g = (Graphics2D) this.getGraphics();
		g.drawImage(buffer, 0, 0, getWidth(), getHeight(), 0, 0, windowWidth,
				windowHeight, this);
		Toolkit.getDefaultToolkit().sync();
		g.dispose();
	}

	public void startGame() {
		initialize();
		while (true) {
			try {
				update();
				checkCollisions();
				drawBuffer(state);
				drawScreen();
				// If we were moving and stopped mid stream, stop it now.
				if (state.equals(State.Map)) {
					if (x % 24 == 0 && y % 24 == 0 && playerMap.x % 24 == 0
							&& playerMap.y % 24 == 0) {
						playerMove = false;
						mapMove = false;
						if (halt)
							// halt all movement
							stopPlayerMap();
						if (change) {
							Random r = new Random();
							int rand = r.nextInt(randEncounter);
							if (rand <= 7) {
								stopPlayerMap();
								randEncounter = 50;
								battle = randomBattle();
								state = State.Transition;
							} else
								rand--;
							change = false;
						}
					}
				}
				Thread.sleep(state.equals(State.Transition)
						|| state.equals(State.PostTransition)
						|| state.equals(State.BattlePlayerDeath) ? 200 : 50);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private Battle randomBattle() {
		Random r = new Random();
		int a = (x / 24) + (playerMap.x / 24);
		int b = (y / 24) + (playerMap.y / 24);
		int aMax = (maps[curMap].image().getWidth() / 24);
		int bMax = (maps[curMap].image().getHeight() / 24);
		int maxNumEnemies = maps[curMap].numEnemies();
		int enm = Math.min((maxNumEnemies * a) / aMax, (maxNumEnemies * b)
				/ bMax);
		String enemy = maps[curMap].getEnemy(enm);
		int number = r.nextInt(3) + 1;
		ArrayList<Player> good = new ArrayList<Player>();
		good.add(playerData);
		ArrayList<Player> baddies = new ArrayList<Player>();
		for (int i = 0; i < number; i++) {
			baddies.add(new Player(enemyData.get(enemy)));
		}
		return new Battle(good, baddies, actions);
	}

	private int fade(int RGB) {
		Color temp = new Color(RGB);
		for (int i = 0; i < trans; i++) {
			temp = new Color(temp.getRed() / 2, temp.getGreen() / 2,
					temp.getBlue() / 2);
		}
		return temp.getRGB();
	}

	private void stopPlayerMap() {
		halt = false;
		if (playerMap.left) {
			playerMap.left = false;
			playerMap.setState(9);
		} else if (playerMap.right) {
			playerMap.right = false;
			playerMap.setState(6);
		} else if (playerMap.up) {
			playerMap.up = false;
			playerMap.setState(3);
		} else if (playerMap.down) {
			playerMap.down = false;
			playerMap.setState(0);
		}
	}
	public int nextLevelExp(){
		return (int) (Math.pow(playerData.getLevel(), 2) * (25 + (playerData.getLevel() > 9 ? 
				Math.ceil(playerData.getLevel() / 1.3) : playerData.getLevel())) + 25);
	}
}
